Super Man 发表于 2015-2-6 22:23:06

逆向双向链表例子驱动

本帖最后由 Super Man 于 2015-2-6 22:33 编辑

typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
*/,y%4QvG7a
f79bd4f8 c745f400000000mov   dword ptr [ebp-0Ch],0 //局部变量清0
ULONG i=0; //计数
   
InitializeListHead(&link_head);//链表地址初始化
f79bd4ff 8d45e8          lea   eax,[ebp-18h] 获得指针
LIST_ENTRY link_head;链表
InitializeListHead(S( nZ]QEG
    __out PLIST_ENTRY ListHead   
    ListHead->Flink = ListHead->Blink = ListHead; //指针都是相同的
}*RpBKm&^7
ZwCreateFile!InitializeListHead:6%nKrK
f79c95f0 8bff            mov   edi,edi   
f79c95f2 55            push    ebp
f79c95f3 8bec            mov   ebp,esp
f79c95f5 8b4508          mov   eax,dword ptr [ebp+8] 获得一个ListHead结构地址 地址   
// ss:0010:f78eec40=f78eec48
f79c95f8 8b4d08          mov   ecx,dword ptr [ebp+8]//同样
f79c95fb 894804          mov   dword ptr [eax+4],ecx   
//ff78eec48 +4 也就是ListHead->Blink = ListHead
f79c95fe 8b5508          mov   edx,dword ptr [ebp+8]
f79c9601 8b4508          mov   eax,dword ptr [ebp+8]   
f79c9604 8902            mov   dword ptr [edx],eax
ListHead->Flink = ListHead
f79c9606 5d            pop   ebp
主要 listhead->Flink和Blink都是指针类型的   
清0


7a234ff 8d45e8          lea   eax, ;获得链表结构变量指针


/*typedef struct _LIST_ENTRY
   struct _LIST_ENTRY *Flink; //指向下一个双链表结构的指针
   struct _LIST_ENTRY *Blink; //指向前一个双链表结构的指针
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
*/

f7a23502 50            push    eax
f7a23503 e8e8000000      call    ZwCreateFile!InitializeListHead
push 链表结构指针。
调用InitializeListHead函数

走进去看看

(注意这是堆栈信息)
[链表结构地址]
ChildEBP RetAddrArgs to Child               
f78e6c38 f7a29508 f78e6c48//双链表指针 e10f8352 00000000 ZwCreateFile!InitializeListHead

InitializeListHead函数源代码
/*wdm.h*/
FORCEINLINE
VOID
InitializeListHead(
    __out PLIST_ENTRY ListHead
    )
{
    ListHead->Flink = ListHead->Blink = ListHead;
}

从函数源代码来看,这个函数的作用,就是把传进来的双链表结构变量的Flink成员和Blink成员都指向自己,这样一个初始化的动作

Disassembly Code:
f7a235f0 8bff            mov   edi,edi
f7a235f2 55            push    ebp
f7a235f3 8bec            mov   ebp,esp ;ebp为堆栈指针
;f7a295f5 8b4508         mov   eax,dword ptr ;得到传进来的参数内容也就是传进来的_LIST_ENTRY结构的地址 ss:0010:f78e6c40=f78e6c48
f7a235f8 8b4d08          mov   ecx,dword ptr
;同上
f7a295fb 894804          mov   dword ptr ,ecx ;ds:0023:f78e6c4c=f78e6c60 ;因为blink是 一个_LIST_ENTRY *类型,所以eax+4这个地址存放的是指针,需要进一步通过指针地址里面存;放的值
;来得到,结构的地址
; Listhead->Blink = ListHead; Blink= 0xf78e6c60(注意,结构地址和上边) [ 0xf78e6c84 - 0xf7a29f9e ] struct _LIST_ENTRY *

f7a235fe 8b5508          mov   edx,dword ptr ;还是得到传进来参数的内容;
f7a23601 8b4508          mov   eax,dword ptr
;同上
f7a29604 8902            mov   dword ptr ,eaxds:0023:f78e6c48=00000000;
;ListHead->Flink = ListHead; 给Flink成员赋值,内容是指向本结构的地址
f7a23606 5d            pop   ebp ;....
f7a23607 c20400          ret   4 ;平衡堆栈




pData = (PMYDATASTRUCT)ExAllocatePool(PagedPool,sizeof (MYDATASTRUCT));//分配内存,
      pData->number = i;
      InsertHeadList(&link_head,&pData->List_Entry);


f7a3554c 8945f8          mov   dword ptr ,eax ;返回ExAllocatePool分配的内存地址
f7a3554f 8b45f8          mov   eax,dword ptr ; pData
f7a35552 8b4df4          mov   ecx,dword ptr ; i
f7a35555 8908            mov   dword ptr ,ecx; == pData->number 的值 , 也就是pData->number = i
f7a35557 8b55f8          mov   edx,dword ptr ; pdata
f7a3555a 83c204          add   edx,4 ;pData+4


/*

typedef struct _MYDATASTRUCT
{
    ULONG number;
    LIST_ENTRY List_Entry;//链表结构
}MYDATASTRUCT,*PMYDATASTRUCT;

*/
地址 +0x4偏移 就是链表结构的地址


f7a3555d 52            push    edx ; pData->List_Entry入栈


f7a3555e 8d45e8          lea   eax, &link_head
f7a35561 50            push    eax; &link_head
f7a35562 e809010000      call    ZwCreateFile!InsertHeadList

InsertHeadList函数源代码(wdm.h)

FORCEINLINE
VOID
InsertHeadList(
    __inout PLIST_ENTRY ListHead,
    __inout __drv_aliasesMem PLIST_ENTRY Entry
    )
{
    PLIST_ENTRY Flink;

    Flink = ListHead->Flink;//得到下一个_LIST_ENTRY结构指针
    Entry->Flink = Flink; // Entry->Flink = Next ListHead
    Entry->Blink = ListHead; //Blink = ListHead
    Flink->Blink = Entry; //Next ListHead ->Blink = pData->Entry
    ListHead->Flink = Entry; // ListHead->Flink = pData->Entry
}

Entry.Flink--> Next_List_Head->Flink
Entry.Blink --> ListHead;

Next_List_Head->Blink =Entry
ListHead->Flink = Entry

f7a35670 8bff            mov   edi,edi
f7a35672 55            push    ebp
f7a35673 8bec            mov   ebp,esp
f7a35675 51            push    ecx
f7a35676 8b4508          mov   eax,dword ptr ;link_head结构变量的地址
f7a35679 8b08            mov   ecx,dword ptr ;取Flink成员的值
f7a3567b 894dfc          mov   dword ptr ,ecx ;存入到PLIST_ENTRY结构变量 Flink中...
f7a3567e 8b550c          mov   edx,dword ptr ; pData->List_Entry变量的地址
f7a35681 8b45fc          mov   eax,dword ptr ss:0010:f78eec30=f78eec48 ;pData->List_Entry = Entry->Flink = Flink = ListHead->Flink
f7a35684 8902            mov   dword ptr ,eax ;pData->List_Entry = Entry->Flink = ListHead->Flink
f7a35686 8b4d0c          mov   ecx,dword ptr ss:0010:f78eec40=e15bd9fc ;得到Entry的地址
f7a35689 8b5508          mov   edx,dword ptr ;listhead
f7a3568c 895104          mov   dword ptr ,edx ds:0023:e15bda00=00000000 ; Entry-blink = listhead
f7a3568f 8b45fc          mov   eax,dword ptr ;Flink
f7a35692 8b4d0c          mov   ecx,dword ptr ; Entry
f7a35695 894804          mov   dword ptr ,ecx ds:0023:f78eec4c=f78eec48 ; Flink->Blink,Entry
f7a35698 8b5508          mov   edx,dword ptr ;ListHead
f7a3569b 8b450c          mov   eax,dword ptr ;Entry
f7a3569e 8902            mov   dword ptr ,eax;ListHead->Flink = Entry
f7a356a0 8be5            mov   esp,ebp
f7a356a2 5d            pop   ebp
f7a356a3 c20800          ret   8

{
    PLIST_ENTRY Flink;

    Flink = ListHead->Flink;//得到下一个_LIST_ENTRY结构指针
    Entry->Flink = Flink; // Entry->Flink = Next ListHead
    Entry->Blink = ListHead; //Blink = ListHead
    Flink->Blink = Entry; //Next ListHead ->Blink = pData->Entry
    ListHead->Flink = Entry; // ListHead->Flink = pData->Entry
}

Entry.Flink--> Next_List_Head->Flink
Entry.Blink --> ListHead;

Next_List_Head->Blink =Entry
ListHead->Flink = Entry

这个关系是这样的

原始的 LIST_ENTRY链表


首先要有一个链表头,那么头插入,就是每次都是从头部插入,具体是这个样子


ListHead->Flink 这个是本身的下一个节点的指针,我们就是把这个指针,换成我们的 一个新的插入节点

也就是

ListHead-> New List_Entry Struct

当然了,这个节点域 也是相互的

所以 这个New List_Entry的Flink 等于 ListHead->Flink 也就是 老的节点,或者叫做Old List_Entry Struct也行
这样~
ListHead->Flink 里面就是变成了 --> New List_Entry,而New List_Entry的 Flink成员当然就是 -->Old List_Entry,
这样就串联了起来
此时 每当有新的节点插入~

ListHead->Flink --> New List_entry->Flink --> old ListEntry 这样~
而New List_entry->Blink成员 就只想 ListHead域,而 old List_Entry->Blink成员 只想 new List_Entry Struct


连起来就是
头结点          新插入的节点   老的节点
ListHead --> New List_Entry <-- Old List_Entry   

经过调试得知的

ListHead->Blink成员时刻等于 第一个插入的节点值

Flink = ListHead->Flink;//得到下一个_LIST_ENTRY结构指针 //第一次的时候就是自身
    Entry->Flink = Flink; // Entry->Flink = Next ListHead
   

Flink->Blink = Entry; //Next ListHead ->Blink = pData->Entry ;//这里.~~就把Blink成员定义为~第一个节点了~~

而且 每次 调用 InsertHeadList改变的只有 Old_List_EnTry->Blink, List_Entry_Flink不会改变,只有被当做new的时候 才会改写一次Flink~~



FORCEINLINE
PLIST_ENTRY
RemoveTailList(
    __inout PLIST_ENTRY ListHead
    )
{
    PLIST_ENTRY Blink; //得到第一个尾部节点,也就是第一个插入的节点
    PLIST_ENTRY Entry;

    Entry = ListHead->Blink; //得到第一个插入的节点
    Blink = Entry->Blink; ;//得到第二个插入的节点
    ListHead->Blink = Blink; // ListHead->Blink变成第二个节点
    Blink->Flink = ListHead; //第二个节点,变成top 节点
    return Entry;返回第一个节点的数据
}

函数源代码(wdm.c)




#define CONTAINING_RECORD(address, type, field) ((type *)((PCHAR)(address) -(ULONG_PTR)(&((type *)0)->field)))
                                                

                                    (MYDATASTRUCT*)((PCHAR)( return Entry) - (ulong_ptr)(&((MYDATASTRUCT *)0)->field) )



pData =CONTAINING_RECORD(pEntry,MYDATASTRUCT,List_Entry);


f7a3b5a7 8945e4          mov   dword ptr ,eax//得到 RemoveTaiList返回的Entry结构地址
f7a3b5aa 8b4de4          mov   ecx,dword ptr ;// 得到
f7a3b5ad 83e904          sub   ecx,4 // 是因为传入到这个宏的是,List_Entry这个结构成员的指针,通过"成员地址 - 成员偏移"的方式,得到结构首地址
/*
typedef struct _MYDATASTRUCT
{
    ULONG number;结构首地址
    LIST_ENTRY List_Entry;//链表结构 首地址+4
}MYDATASTRUCT,*PMYDATASTRUCT;

*/

f7a3b5b0 894df8          mov   dword ptr ,ecx
f7a3b5b3 8b55f8          mov   edx,dword ptr ss:0010:f78e6c58=e184d3e8 ;pData->number
f7a3b5b6 8b02            mov   eax,dword ptr ;得到值
f7a3b5b8 50            push    eax; 准备输出
f7a3b5b9 6840b7a3f7      push    offset ZwCreateFile! ?? ::FNODOBFM::`string' (f7a3b740)
f7a3b5be e805010000      call    ZwCreateFile!DbgPrint (f7a3b6c8)
f7a3b5c3 83c408          add   esp,8

反汇编代码



至此双链表逆向完毕~~~
- -

代码~~~~~~~~
00000: VOID LinkList_One()
00001: {
00002:   /*
    typedef struct _LIST_ENTRY {
    struct _LIST_ENTRY *Flink;
    struct _LIST_ENTRY *Blink;
    } LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
    */
00003:
00004:   LIST_ENTRY link_head;//链表结构
00005:   PMYDATASTRUCT pData;//链表指针
00006:   ULONG i=0; //计数
00007:   KSPIN_LOCK spin_lock;//锁,对付多线程
00008:   KIRQL irql;
00009:   //初始化链表
00010:
00011:   InitializeListHead(&link_head);
00012:   KeInitializeSpinLock(&spin_lock);//初始化一个锁
00013:
00014:   //插!
00015:   KdPrint((" Begin Insert to link list~~\n"));
00016:
00017:   //锁住
00018:
00019:   KeAcquireSpinLock(&spin_lock,&irql);
00020:   //干活!
00021:
00022:   for (i=0;i<10;i++)
00023:   {
00024:         pData = (PMYDATASTRUCT)ExAllocatePool(PagedPool,sizeof (MYDATASTRUCT));//分配内存,
00025:         pData->number = i;
00026:         InsertHeadList(&link_head,&pData->List_Entry);
00027:
00028:   }
00029:
00030:   KeReleaseSpinLock(&spin_lock,irql);
00031:
00032:
00033:   //取数据
00034:
00035:   KdPrint((" Begin remove link list\n"));
00036:
00037:   //锁~住
00038:   KeAcquireSpinLock(&spin_lock,&irql);
00039:
00040:
00041:   while (!IsListEmpty(&link_head))
00042:   {
00043:
00044:         PLIST_ENTRY pEntry = RemoveTailList(&link_head);
00045:
00046:         //得到节点数据
00047:         pData =CONTAINING_RECORD(pEntry,MYDATASTRUCT,List_Entry);
00048:
00049:         KdPrint((" %d\n",pData->number));
00050:         ExFreePool(pData);
00051:   }
00052:
00053:   KeReleaseSpinLock(&spin_lock,irql);
00054: }
00055:
00056:


n69l67399 发表于 2015-2-6 23:02:45

啥玩应呀

zhuzhuli 发表于 2015-4-4 15:17:51

报告!别开枪,我就是路过来看看的。。。

︶ㄣ彯逸尐苏 发表于 2015-5-23 10:43:15

只有对楼主表示感谢,才能表达我现在的心情!

juanzi 发表于 2015-6-2 14:54:30

你好 我只是看看不说话,看我就走。

wan 发表于 2015-6-2 15:09:22

支持楼主,绝对顶你...谢谢!

xinxi 发表于 2015-8-13 04:35:13

高手云集 马上来看看

戒不掉的烟々 发表于 2015-9-24 18:31:54

楼主天天快乐,吉祥如意!
页: [1]
查看完整版本: 逆向双向链表例子驱动