转自:http://www.0xaa55.com/thread-1385-1-1.html

之前做过ldr遍历的操作,发现第一项竟然是空,也就是大部分元素都是0,下面来揭示一下原理:

经过研究,其实Ldr链表得第一项为头结点,为PEB_LDR_DATA结构,而其他所有项均为LDR_DATA_TABLE_ENTRY结构
Ldr的创建:ldrinit.c -> LdrpInitializeProcess

PEB_LDR_DATA PebLdr

LdrpInitializeProcess   初始化进程时用空项PebLdr创建Ldr
    Peb->Ldr = &PebLdr;
    InitializeListHead(&PebLdr.InLoadOrderModuleList);
    InitializeListHead(&PebLdr.InMemoryOrderModuleList);
    InitializeListHead(&PebLdr.InInitializationOrderModuleList);
    PebLdr.Length = sizeof(PEB_LDR_DATA);
    PebLdr.Initialized = TRUE;
        
LdrUnloadDll和LdrpLoadDll分别会进行对Ldr这3个链表卸载和增添节点操作,而顺序不同:
Load时如果发现未加载dll则会增加节点,会先添加InMemoryOrderModuleList  InLoadOrderModuleList  两个链表增加节点,之后操作InInitializationOrderModuleList,之后调用DllMain初始化
而Unload的时候若发现引用计数为0则会删除节点,会先对InMemoryOrderModuleList InInitializationOrderModuleList 两个链表删除节点,之后调用DllMain清理,最后删除InLoadOrderModuleList节点
#define RemoveEntryList(e) do { PLIST_ENTRY f = (e)->Flink, b = (e)->Blink; f->Blink = b; b->Flink = f; (e)->Flink = (e)->Blink = NULL; } while (0)
可见删除链表操作为将该项后一个节点直接连接到前一个节点,并且将当前节点的首尾指向NULL,因此通过判断Flink=0 可以判断某DLL正在被卸载
        
正确的遍历Ldr LIST_ENTRY方法:
    ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
    Next = ListHead->Flink;
    while (Next != ListHead)//跳过头结点即可
        {
                 Next = Next->Flink;
        }

而ldr结构图如下:
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 InLoadOrderLinks;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    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;
        
当时我遍历的时候将Head当成LDR_DATA_TABLE_ENTRY,自然数据是不对的~~

为何遍历Ldr会得到空项?的更多相关文章

  1. Java的poi技术遍历Excel时进行空Cell,空row,判断

    /** * 导入信息 */ @Override public List<Object> add(HttpServletRequest request) { // TODO Auto-gen ...

  2. js中遍历删除数组中的项(项目中遇到的问题解决)

    代码如下: for (var key=0;key<$scope.pageContent.messages.length;key++){ if($scope.pageContent.message ...

  3. checkbox遍历操作, 提交所有选中项的值

    <div class="content_list pad_10 hidden" > <h3>修改可配送地区</h3> <input typ ...

  4. Winform 遍历 ListBox中的所有项

    foreach(DataRowView row in listBox.Items ) { MessageBox.Show(row["displayMember"].ToString ...

  5. PHP数组去空项

    $strDelCodes = "A;B;;C;;C;D;;;D;D";$rsArray = array_values (array_unique (array_diff (spli ...

  6. 先序遍历创建二叉树,对二叉树统计叶子节点个数和统计深度(创建二叉树时#代表空树,序列不能有误)c语言

    #include "stdio.h" #include "string.h" #include "malloc.h" #define NUL ...

  7. C++树的插入和遍历(关于指针的指针,指针的引用的思考)

    题目 写一个树的插入和遍历的算法,插入时按照单词的字典顺序排序(左边放比它"小"的单词,右边放比它"大"的单词),对重复插入的单词进行计数. 程序源码 #inc ...

  8. PEB及LDR链

    PEB地址的取得在NT内核系统中fs寄存器指向TEB结构,TEB+0x30处指向PEB结构,PEB+0x0c处指向PEB_LDR_DATA结构,PEB_LDR_DATA+0x1c处存放一些指向动态链接 ...

  9. 二叉树遍历入门 Lebal:research

    解决二叉树遍历的画法 对于二叉树的基本概念,一般学生都知道,但对于二叉树的遍历,在实际运用中可以发现很多问题,这里提供一次性彻底解决这个问题的方法. 二叉树的遍历 二叉树的遍历是指不重复地访问二叉树中 ...

随机推荐

  1. 使用Web Application Stress Tool 进行压力测试

    1.在测试客户端机器上启动Web Application Stress Tool,在弹出的“建立新脚本”对话框中选择“Record”按钮: 2.在“Record”参数设置第一步中,所有的checkbo ...

  2. HDU2054_A == B ?【模拟题】【大数】【水的问题】

    A == B ? Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  3. swift锁屏播放,音乐进度更新,专辑,歌手名显示

    我自己用的音乐播放器是自带的AVPlayer 导入头文件#import <MediaPlayer/MediaPlayer.h> 远程控制事件接收与处理- (void)viewWillApp ...

  4. 【最小费用最大流】【HDU1533】【Going Home】

    题意 给你一个类似这样的图 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 问所有H移动到所有m上花费最少的步数 以所有H ...

  5. (转)轻量级数据库 SQLite

    SQLite Expert – Personal Edition SQLite Expert 提供两个版本,分别是个人版和专业版.其中个人版是免费的,提供了大多数基本的管理功能. SQLite Exp ...

  6. IE下图片切换的时候,图片总是切换不成功---根本问题是IE缓存图片

    作为WEB设计者,为了在网页展示上加强用户体验,经常会利用图象载入显示状态方法,这自然需要Image对象的onload事件. 在firefox浏览器下完成开发后,可是在IE浏览器中进行调试总不能被调用 ...

  7. base64图片在各种浏览器的兼容性处理

    IE浏览器目前最高的版本是v11,而微软放弃了IE,转向新的浏览器开发,并取名为Edge.base64图片在IE9及以后的图片均能显示没有问题,而Firefox, Chrome, Safari等非IE ...

  8. 对FineU框架Grid多表头合计行导出Excel的回顾

    年前用FineUI开发遇到了这样一个问题,Grid多表头合计行不能导出,后面到官方示例找了一下,庆幸的是找到了多表头的导出示例.然后当时为了省事,直接就复制粘贴完事,也没有仔细的研究代码.后来运行一看 ...

  9. C++#define的用法(含特殊)

    1 无参宏定义无参宏的宏名后不带参数.其定义的一般形式为:    #define 标识符 字符串其中的“#”表示这是一条预处理命令.凡是以“#”开头的均为预处理命令.“define”为宏定义命令.“标 ...

  10. javascript 数据结构和算法读书笔记 > 第一章 javascript的编程环境和模型

    1.变量的声明和初始化 必须使用关键字 var,后跟变量名,后面还可以跟一个赋值表达式. var name; var age = 5; var str = 'hello'; var flg = fal ...