通过TEB/PEB枚举当前进程空间中用户模块列表_c语言ldr枚举dll-程序员宅基地

技术标签: struct  null  安全 黑客  list  microsoft  windows  数据结构  

 http://icwin.net/ShowArtitle.ASP?art_id=6315&cat_id=39

实在没精力找出最早介绍该项技术的文章,尽管很想知道答案。29A杂志中大量使用
该技术([8]),并辅以文字说明,推荐阅读。下面操作是在windbg中进行的,提前在
注册表中设置好AeDebug,执行vulnerable_0.exe,进入windbg调试状态。也可通过
其它办法进入windbg调试状态。

段选择子FS所对应的段即当前线程TEB(Thread Environment Block),即FS:0指向TEB。

> dg @fs
Selector Base Limit Type DPL Size Gran Pres
-------- -------- -------- ---------- --- ------- ---- ----
0038 7ffde000 00000fff Data RW Ac 3 Big Byte P
> r $teb
$teb=7ffde000

TEB[0x30]是一个指向当前进程PEB(Process Environment Block)的指针。大家都这
么说,可他们如何知道这个偏移的,你该上哪去找TEB的数据结构定义,不同系统上
该结构定义一致吗。有这么多疑问,可绝大多数文章没有告诉你捞鱼的办法,只给你
鱼,你一定有种意尤未尽的郁闷。呵,了解,下面就是捞鱼的办法,windbg的dt命令:

> dt ntdll!*teb* (列出匹配通配符的结构名)
ntdll!_TEB
... ...
> dt -v -r ntdll!_TEB
struct _TEB, 64 elements, 0xfb4 bytes
0x000 NtTib : struct _NT_TIB, 8 elements, 0x1c bytes
0x01c EnvironmentPointer : Ptr32 to Void
0x020 ClientId : struct _CLIENT_ID, 2 elements, 0x8 bytes
0x028 ActiveRpcHandle : Ptr32 to Void
0x02c ThreadLocalStoragePointer : Ptr32 to Void
0x030 ProcessEnvironmentBlock : Ptr32 to struct _PEB, 66 elements, 0x210 bytes
... ...

偏移、名称、类型、大小等等一应俱全地列举在此。万事不求人是不对的,指望别人
老来求自己更是不对的,藏着掖着是要一起挨米国鬼子打的。无论你用什么系统,去
下载相应版本的windbg,然后用上述办法自己核实偏移。MS一贯擅长保持向后兼容性,
这是它巨大成功的基础,类似0x30这样的偏移,被改动的可能性并不大。

号称新版Platform SDK的ntpsapi.h文件中直接给出了TEB的数据结构,我的不够新,
没找着这个文件。反正dt命令够我用了,懒得深究。

顺便提个事。肯定有人见过这样的代码,之后eax将指向PEB:

mov eax,fs:[18h]
mov eax,[eax 30h]

看完本文新的介绍,你肯定在疑惑中,这样的代码居然也能成功获取PEB地址,惟
一的解释就是fs:[18h]与fs:[0h]指向同一处。TEB结构第一成员是NT_TIB结构,后者
的Self成员指向自身这个NT_TIB结构,碰巧这个NT_TIB结构是TEB结构第一成员,
于是可以认为Self指向TEB。Self的偏移是0x18,就这么简单。

> dt -v _NT_TIB $teb
struct _NT_TIB, 8 elements, 0x1c bytes
0x000 ExceptionList : 0x0012ffb0 struct _EXCEPTION_REGISTRATION_RECORD, 2 elements, 0x8 bytes
0x004 StackBase : 0x00130000
0x008 StackLimit : 0x0012b000
0x00c SubSystemTib : (null)
0x010 FiberData : 0x00001e00
0x010 Version : 0x1e00
0x014 ArbitraryUserPointer : (null)
0x018 Self : 0x7ffde000 struct _NT_TIB, 8 elements, 0x1c bytes

换句话说,ds:[7ffde000h]与fs:[0h]这两个不同的逻辑地址对应同一个线性地址。
参看<<IA-32 Software Developer's Manual. Volume 3>>([12])的3.1小节,下面是
Intel的标准定义:

逻辑地址

段选择子(16-bits):段内偏移(32-bits)

也叫远指针。程序中寻址时只能使用逻辑地址。没有办法禁用段机制,但有办法
禁用分页机制。

线性地址

逻辑地址经GDT、LDT转换后得到线性地址。

只需一条代码即可获取PEB地址:

mov eax,fs:[30h]

> dd @fs:30 L1
0038:00000030 7ffdf000
> dt ntdll!_TEB 7ffde000
0x000 NtTib : _NT_TIB
0x01c EnvironmentPointer : (null)
0x020 ClientId : _CLIENT_ID
0x028 ActiveRpcHandle : (null)
0x02c ThreadLocalStoragePointer : (null)
0x030 ProcessEnvironmentBlock : 0x7ffdf000
... ...
> !teb
TEB at 7ffde000
ExceptionList: 0012ffb0
... ...
PEB Address: 7ffdf000
... ...
> r $peb
$peb=7ffdf000
> dd $teb 30 L1 (当前基是16进制)
7ffde030 7ffdf000

无数种办法可以得到指向PEB的指针0x7ffdf000。

Inside 2K([9])<<Table 7-6 Windows 2000 User Process Address Space Layout>>
中直接将TEB、PEB定位在0x7ffde000、0x7ffdf000。一般来说是这样的,可是不建议
依赖硬编码地址。这就看当前最紧要的是广泛兼容性还是压缩代码空间。注意,讨论
前提是编写exploit、shellcode、virus,最终可能要汇编化的,而非常规编程。

PEB[0x0c]指向PEB_LDR_DATA结构,该结构有三个成员均可用于枚举当前进程空间中
的模块列表,区别在于加载顺序、内存顺序、初始化顺序。这是三个双向循环链表,
遍历时留神。

> dt -v -r ntdll!_PEB
struct _PEB, 66 elements, 0x210 bytes
0x000 InheritedAddressSpace : UChar
0x001 ReadImageFileExecOptions : UChar
0x002 BeingDebugged : UChar
0x003 SpareBool : UChar
0x004 Mutant : Ptr32 to Void
0x008 ImageBaseAddress : Ptr32 to Void
0x00c Ldr : Ptr32 to struct _PEB_LDR_DATA, 7 elements, 0x28 bytes
... ...
> dt -v -r ntdll!_PEB_LDR_DATA
struct _PEB_LDR_DATA, 7 elements, 0x28 bytes
0x000 Length : Uint4B
0x004 Initialized : UChar
0x008 SsHandle : Ptr32 to Void
0x00c InLoadOrderModuleList : struct _LIST_ENTRY, 2 elements, 0x8 bytes
0x014 InMemoryOrderModuleList : struct _LIST_ENTRY, 2 elements, 0x8 bytes
0x01c InInitializationOrderModuleList : struct _LIST_ENTRY, 2 elements, 0x8 bytes
0x024 EntryInProgress : Ptr32 to Void
> dt -v -r ntdll!_LIST_ENTRY
struct _LIST_ENTRY, 2 elements, 0x8 bytes
0x000 Flink : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
0x004 Blink : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
> dd $peb c L1
7ffdf00c 00241e90
> dt ntdll!_PEB_LDR_DATA 00241e90
0x000 Length : 0x28
0x004 Initialized : 0x1 ''
0x008 SsHandle : (null)
0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x241ec0 - 0x2429d8 ]
0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x241ec8 - 0x2429e0 ]
0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x241f28 - 0x2429e8 ]
0x024 EntryInProgress : (null)
> dl 241f28 ffff 2 (注意Flink形成循环链表)
00241f28 00241fd0 00241eac
00241fd0 00242118 00241f28
00242118 00242258 00241fd0
00242258 002423a0 00242118
002423a0 00242300 00242258
00242300 002424e0 002423a0
002424e0 00242440 00242300
00242440 00242770 002424e0
00242770 002428a8 00242440
002428a8 00242808 00242770
00242808 002429e8 002428a8
002429e8 00241eac 00242808
00241eac 00241f28 002429e8
> dlb 2429e8 ffff 2 (注意Blink形成循环链表)
002429e8 00241eac 00242808
00242808 002429e8 002428a8
002428a8 00242808 00242770
00242770 002428a8 00242440
00242440 00242770 002424e0
002424e0 00242440 00242300
00242300 002424e0 002423a0
002423a0 00242300 00242258
00242258 002423a0 00242118
00242118 00242258 00241fd0
00241fd0 00242118 00241f28
00241f28 00241fd0 00241eac
00241eac 00241f28 002429e8

单从windbg所给出的信息,只能看出三个双向循环链表的存在,每个链表结点上只有
前向指针、后向指针,如何获取最终的模块信息呢。其实这是很关键的问题,遗憾的
是某些文章不知出于什么动机刻意回避该问题。

Reactos与Tomasz Nowak提供了未公开的LDR_MODULE数据结构,我把偏移标出来了,
方便计算:

typedef struct _LDR_MODULE
{
LIST_ENTRY InLoadOrderModuleList; // 0x00
LIST_ENTRY InMemoryOrderModuleList; // 0x08
LIST_ENTRY InInitializationOrderModuleList; // 0x10
PVOID BaseAddress; // 0x18
PVOID EntryPoint; // 0x1c
ULONG SizeOfImage; // 0x20
UNICODE_STRING FullDllName; // 0x24
UNICODE_STRING BaseDllName; // 0x2c
ULONG Flags; // 0x34
SHORT LoadCount; // 0x38
SHORT TlsIndex; // 0x3a
LIST_ENTRY HashTableEntry; // 0x3c
ULONG TimeDateStamp; // 0x44
// 0x48
} LDR_MODULE, *PLDR_MODULE;

郑重推荐<<The Undocumented Functions For Microsoft Windows NT/2000>>,逆反
心理促使我一定要让大家都知道这个数据结构引自何处([10])。

说点题外话,Google是你的朋友。Windows底层编程在中国不知因为什么而显得资料
罕见,结果以前给我一个错觉,Windows底层编程举步维艰。后来因工作原因Google
时向Windows做了点偏移,发现国外此类编程资料并非如想像的那般罕见,有些人共
享出完整源代码后只是说如果感觉有帮助能否在网上订份小礼物给他,我是没境外信
用卡,否则一定订份小礼物给他。我还发现一件有意思的事,有人注明原创的时候
居然没有任何参考资源,不巧的是我看过的英文文章实在有点烂多,当创意、技巧、
代码片段重合得太多时,就有种无奈的感概。有鉴于此,己所不欲、勿施与人,写此
类型文章时一概不敢宣称是原创、翻译,撑死了是笔记,还生怕漏了引自何处。也可
能是我水平低,才如此。水平一高,就不便引他人之文了,谁知道呢。呵,很小的时
候听爹说过一句话,吃饭的永远不要责怪做饭的,确实如此,所以就不多评价了。

建议大家写文章时认真负责地给参考资源,有URL的都注明URL,不费什么事。

扯远了,回到LDR_MODULE结构上来,三个双向循环链表的结点正是该结构。

按加载顺序遍历:

!list -t _LIST_ENTRY.Flink -x !ustr -a 24 241ec0
!list -t _LIST_ENTRY.Flink -x !ustr -a 2c 241ec0

按内存顺序遍历:

!list -t _LIST_ENTRY.Flink -x !ustr -a 1c 241ec8
!list -t _LIST_ENTRY.Flink -x !ustr -a 24 241ec8

按初始化顺序遍历:

> !list -t _LIST_ENTRY.Flink -x !ustr -a 14 241f28
String(58,520) at 00241f3c: D:WINDOWSSystem32ntdll.dll
String(64,66) at 00241fe4: D:WINDOWSsystem32kernel32.dll
... ...
> !list -t _LIST_ENTRY.Flink -x !ustr -a 1c 241f28
String(18,20) at 00241f44: ntdll.dll
String(24,26) at 00241fec: kernel32.dll
... ...

一般前向遍历链表时,第一个节点对应ntdll.dll,第二个结点对应kernel32.dll,
我们不太关心其它模块。

编程枚举用户模块列表时,重点显示BaseAddress、FullDllName成员。总结一下全过
程:

a. 从fs:[30h]获取PEB地址

b. 从PEB[0x0c]获取Ldr地址

c. 从Ldr[0x0c]获取InLoadOrderModuleList.Flink

d. 从InLoadOrderModuleList.Flink开始前向遍历循环链表

e. 显示LDR_MODULE结构的BaseAddress、FullDllName成员。

下面是完整的C语言演示程序,汇编化留到编写完整shellcode时进行。

--------------------------------------------------------------------------
/*
* -----------------------------------------------------------------------
* Compile : For x86/EWindows XP SP1 & VC 7
* : cl EnumModule.c /nologo /Os /G6 /W3 /D WIN32 /D NDEBUG /D _CONSOLE /link /RELEASE
* :
* Create : 2003-08-12 11:36
* Modify :
* -----------------------------------------------------------------------
*/

/*
* 按加载顺序遍历双向循环链表
*/

#include <stdio.h>
#include <stdlib.h>

#pragma comment( linker, /INCREMENTAL:NO )
#pragma comment( linker, /subsystem:console )

int __cdecl main ( int argc, char * argv[] )
{
void *PEB = NULL,
*Ldr = NULL,
*Flink = NULL,
*p = NULL,
*BaseAddress = NULL,
*FullDllName = NULL;

__asm
{
mov eax,fs:[0x30]
mov PEB,eax
}
printf( PEB = 0xXn, PEB );
Ldr = *( ( void ** )( ( unsigned char * )PEB 0x0c ) );
printf( Ldr = 0xXn, Ldr );
Flink = *( ( void ** )( ( unsigned char * )Ldr 0x0c ) );
printf( Flink = 0xXn, Flink );
p = Flink;
do
{
BaseAddress = *( ( void ** )( ( unsigned char * )p 0x18 ) );
FullDllName = *( ( void ** )( ( unsigned char * )p 0x28 ) );
printf( p = 0xX 0xX , p, BaseAddress );
wprintf( Lsn, FullDllName );
p = *( ( void ** )p );
}
while ( Flink != p );
return( EXIT_SUCCESS );
} /* end of main */
--------------------------------------------------------------------------

执行效果如下。可以看出,尽管是循环链表,也可通过判断BaseAddress是否为NULL
来结束遍历。

> EnumModule
PEB = 0x7FFDF000
Ldr = 0x00241E90
Flink = 0x00241EC0
p = 0x00241EC0 0x00400000 X:EnumModule.exe
p = 0x00241F18 0x77F50000 X:XPSystem32ntdll.dll
p = 0x00241FC0 0x77E60000 X:XPsystem32kernel32.dll
p = 0x00241E9C 0x00000000
>

☆ 参考资源

[ 8] <a href=/'http://vx.netlux.org/vx.php?id=z001/' target=/'_blank/'> target=_blank>http://vx.netlux.org/vx.php?id=z001</a> (29A杂志)

Virus Writing Guide 1.00 for Win32 - Billy Belceb
29A-4.202

A guide to the latest methods to retrieve API's in a Win32 environment - LethalMind
29A-4.227

Gaining important datas from PEB under NT boxes - Ratter
29A-6.024

[ 9] <<Inside Microsoft Windows 2000 Third Edition>> - David A. Solomon, Mark E. Russinovich

[10] The Undocumented Functions For Microsoft Windows NT/2000
<a href=/'http://undocumented.ntinternals.net/ntundoc.chm/' target=/'_blank/'> target=_blank>http://undocumented.ntinternals.net/ntundoc.chm</a>

[12] Intel Architecture Software Developer's Manual. Volume 1
<a href=/'ftp://download.intel.com/design/PentiumII/manuals/24319002.pdf/' target=/'_blank/'> target=_blank>ftp://download.intel.com/design/PentiumII/manuals/24319002.pdf</a>

Intel Architecture Software Developer's Manual. Volume 2
<a href=/'ftp://download.intel.com/design/PentiumII/manuals/24319102.pdf/' target=/'_blank/'> target=_blank>ftp://download.intel.com/design/PentiumII/manuals/24319102.pdf</a>

Intel Architecture Software Developer's Manual. Volume 3
<a href=/'ftp://download.intel.com/design/PentiumII/manuals/24319202.pdf/' target=/'_blank/'> target=_blank>ftp://download.intel.com/design/PentiumII/manuals/24319202.pdf</a>
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/TO_YGY/article/details/1652481

智能推荐

在compute node上安装neutron时,出错neutron ValueError: :5672_在执行脚本进行neutron网络服务安装时报错是什么原因?-程序员宅基地

文章浏览阅读1.1k次。这个是由于没有按住奥_在执行脚本进行neutron网络服务安装时报错是什么原因?

SSM整合_<!--过滤静态资源--> <mvc:resources location="/css/" -程序员宅基地

文章浏览阅读93次。springmvc(view 视图层) ,spring(service业务层) ,Mybatis (dao持久层)1.spring整合springmvc:springmvc配置文件:<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans..._

"当你有一个目标时,就请朝着它努力,你一定会成功的"--世界杯进球记录第一射手克劳泽...-程序员宅基地

文章浏览阅读212次。德国足球队老将克劳泽,一生四次参加世界杯(2002, 2006, 2010, 2014),总共打入16粒进球,是世界杯进球记录拥有者。他的成功,折射出德国人身上优秀的光芒。●童年克洛泽是在1978年出生在波兰的奥博莱,但那里是波兰最大的德裔民族聚居地。从血统上来讲,克洛泽祖祖辈辈都是日耳曼人,而Klose就是最古老的日耳曼姓氏之一。  造成这一切的都是“历史遗留问题”,奥博莱地区在二..._德国球星克劳泽射门

bootstrap练习题-程序员宅基地

文章浏览阅读1.6k次。什么是BootStrap框架Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架。Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的前端框架,之所以它能够帮我们快速构建一个前端应用是因为它实现了很多默认的网页样式效果,我们只需要引用它实现的效果即可获得一个漂亮的网页Html、Css和BootStrap框架的关系是什么1.bootstrap就是实现了很多..._bootstrap练习题

Dword、LPSTR、LPWSTR、LPCSTR、LPCWSTR、LPTSTR、LPCTSTR_pcstr 变量-程序员宅基地

文章浏览阅读529次。L表示long指针,这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32为操作系统中, long指针和near指针及far修饰符都是为了兼容的作用,没有实际意义。即win32中,long,near,far指针与普通指针没有区别,LP 与P是等效的。P表示这是一个指针。 T表示_T宏,这个宏用来表示你的字符是否使用UNICODE, 如果你的程序定义了_pcstr 变量

numpy专题:ndarray常用函数及属性_在ndarray中用什么函数创建等比数列-程序员宅基地

文章浏览阅读474次。import numpy as np#创建一位数组arr1 = np.array([1,2,3,4])print(arr1)[1 2 3 4]#创建二维数组(4行3列)arr2 = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])print(arr2)[[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]]#查看数组属性print('_在ndarray中用什么函数创建等比数列

随便推点

生活大爆炸第三季 那些精妙的台词翻译_tushy face-程序员宅基地

文章浏览阅读2k次。第三季的精彩语录值得记录。_tushy face

邮件发送与接收,支持163邮箱、outlook邮箱、exchange邮箱_. 集成&自动化中配置发送邮件节点,发件人邮箱账号支持哪些邮箱类型-程序员宅基地

文章浏览阅读2.4k次。邮件发送与接收,支持163邮箱、outlook邮箱、exchange邮箱依赖的jar包邮件收发公共服务层实现package com.example.demo.service.impl;import com.example.demo.model.EmailMessageBO;import com.example.demo.model.EmailSendBO;import com.example.demo.model.FileBean;import com.example.demo.serv_. 集成&自动化中配置发送邮件节点,发件人邮箱账号支持哪些邮箱类型

android pppd参数介绍,android 3G pppd 调试记录-程序员宅基地

文章浏览阅读675次。android 3G pppd 调试记录。1. JAVA 部分android/development/data/etc/apns-conf_sdk.xml ---> system/etc/apns-conf.xml注意 apns 的版本,apn="3gnet"mcc="460"mnc="01"proxy=""port=""user=""server=""password=""type..._pppd 中拨号mcc和mnc 配置

php okhttp3 上传文件,Android使用OKHttp库实现视频文件的上传到服务器功能-程序员宅基地

文章浏览阅读697次。1 服务器接口简介此处我使用的服务器接口是使用Flask编写,具体实现代码:# -*- coding: utf-8 -*-from flask import Flask, render_template, jsonify, requestimport timeimport osimport base64app = Flask(__name__)UPLOAD_FOLDER = 'E:\myuploa..._okhttp3上传视频

android常用的必备基础知识_android必背知识-程序员宅基地

文章浏览阅读151次。首先从四大组件说起: Activity: 生命周期: activity三种状态:运行(运行在最前端)、停止(不可见,完全被覆盖)、暂停(可见,但前端还有其他activity) 生命周期相关的方法:onCreate-onStart-onResume-onPause-onStop-onDestory-onRestart 切换时如果要保存数据, 可以重写: onSaveInstanceStat..._android必背知识

matplotlib的imshow函数显示灰度图像要设置vmin和vmax2个参数_imshow vmin-程序员宅基地

文章浏览阅读4.1k次,点赞4次,收藏13次。matplotlib的imshow函数在显示灰度图像的时候要设置vmin和vmax2个函数_imshow vmin