转自: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. Hibernate征途(三)之CRUD

    上篇博客<Hibernate征途(二)之基础与核心>介绍了Hibernate的基础内容和核心内容,这篇博客简单实践一下.第一篇博客也说过Hibernate是一种JDBC的简化方案,既然是和 ...

  2. 图片延迟加载并等比缩放,一个简单的JQuery插件

    使用方法: $(".viewArea img").zoom({height:74,width:103}); (function($){ $.fn.zoom = function(s ...

  3. 蜗牛爱课 -- iOS 设置UIButton的字体的大小、显示位置、大小

    /设置按钮上的自体的大小 //[btn setFont: [UIFont systemFontSize: 14.0]];    //这种可以用来设置字体的大小,但是可能会在将来的SDK版本中去除改方法 ...

  4. 二.ubuntu14.04 3D特效设置

    一.如果按照第一篇都设置好了(显卡驱动等都已经正常),然后 1.安装CCSM设置管理器 用鼠标点击屏幕左侧Unity程序启动栏中的“Ubuntu软件中心”(有“A”字形的公文包图标), 在弹出的“Ub ...

  5. bootstrap之noConflict的详解

    翻开推特框架,不经发现,几乎所有的插件都会出现noConflict的写法来防止和其他的插件冲突!我们以button.js为例子,打开其源代码发现 如下: var old = $.fn.button $ ...

  6. Which PHP mode? Apache vs CGI vs FastCGI

    Which PHP mode? Apache vs CGI vs FastCGI There are multiple ways to execute PHP scripts on a web ser ...

  7. python-凯撒密码

    凯撒密码 简介:凯撒密码(Caesar)是最早的代换密码,对称密码的一种 算法:将每个字母用字母表中它之后的第k(称作位移值)个字母替代 代码: #-*-coding:utf-8-*- __autho ...

  8. iOS把一个简单的图形变成一个圆

    push是定义的一个button push.layer.masksToBounds = YES; push.layer.cornerRadius = 100; push.layer.borderWid ...

  9. python 网络编程第三版

    为服务端增加多线程解决方案 1.服务端代码如下: ***这个版本并没有真正的起到多线程的作用,主要原因在于t.join():以后的版本会改进这个问题*** #!/usr/bin/python #!co ...

  10. 谈谈ILDasm的功能限制与解除

    原文:谈谈ILDasm的功能限制与解除 首先,我在此申明,此文并不是教别人突破限制,我们只是用学习的眼光看问题 大家都知道ILDasm是.NET程序的反编译工具,它是由Microsoft提供的反编译工 ...