zoukankan      html  css  js  c++  java
  • 栈溢出笔记1.6 地址问题(1)

    前面的Shellcode中,我使用的都是自己XP机器上的硬编码地址。不论什么时候在Shellcode中使用硬编码地址都不是个好主意,这一点与动态库的重定位相似,一旦系统环境和程序编译设置发生变化。Shellcode差点儿肯定会失效。因此。我们要找到更好一点的方法。

    前面的Shellcode中,我用到了例如以下几个硬编码地址。它们的含义例如以下:
    这里写图片描写叙述
    当中。LoadLibraryA的作用比較特殊,我们用它来载入user32.dll库。

    如今我们要换掉这些硬编码地址。那么,怎样得到这些API函数的地址呢?在动态链接库中获取函数地址有一个专门的函数——GetProcAddress,这个函数的原型例如以下:

    /*****************************************************************************/
    FARPROC WINAPI GetProcAddress(
      _In_ HMODULE hModule,
      _In_ LPCSTR  lpProcName
    );
    /*****************************************************************************/

    这个函数第一个參数为模块的句柄,能够调用LoadLibraryA获得,第二个參数为函数名称。

    这种话。MessageBoxA和ExitProcess都能够使用这种方式来获取。可是这依赖于两个函数:LoadLibraryA和GetProcAddress,那这两个函数的地址又怎么得到呢?

    这两个函数都位于kernel32.dll。kernel32.dll肯定会载入。不须要我们自己载入。因此,如今的问题就是怎样从kernel32.dll中找到LoadLibraryA和GetProcAddress的地址?

    接下来就须要一点Windows内核和PE文件格式的知识了。我们知道,kernel32.dll为PE格式的动态链接库,要导出的函数放在PE文件的导出表中,因此,为了获取LoadLibraryA和GetProcAddress的地址,我们须要手动解析kernel32.dll的导出表。但在这之前,我们须要知道kernel32.dll在内存中的位置,也就是kernel32.dll的基地址。

    因此。问题总结为下面:
    (1)怎样获取kernel32.dll的基地址?
    (2)怎样在kernel32.dll的导出表中找到LoadLibraryA和GetProcAddress的地址?

    先来解决第一个问题。我们知道。一个进程执行的时候。除了载入exe文件外,所依赖的.dll也会映射到进程的虚拟地址空间中。那么。这些载入的dll也是进程的財产。因此,进程会保存它们的信息。进程的信息都保存在PEB结构中。当中的Ldr(偏移为0xc0)指向一个PEB_LDR_DATA结构,这个结构保存的进程已载入模块的信息。

    这个结构例如以下:

    /*****************************************************************************/
    typedef struct _PEB_LDR_DATA
    {
     ULONG Length;          // +0x00
     BOOLEAN Initialized;   // +0x04
     PVOID SsHandle;            // +0x08
     LIST_ENTRY InLoadOrderModuleList;      // +0x0c
     LIST_ENTRY InMemoryOrderModuleList;    // +0x14
     LIST_ENTRY InInitializationOrderModuleList;    // +0x1c
    } PEB_LDR_DATA,*PPEB_LDR_DATA;      // +0x24
    /*****************************************************************************/

    Windows并未全然公开(文档化)此结构。这是网上的版本号,我们也能够通过Windbg来得到,这是我XP SP3机器上的该结构:
    这里写图片描写叙述
    图37

    这个结构的重点在于后面三个链表:InLoadOrderModuleList、InMemoryOrderModuleList和InInitializationOrderModuleList。从名称上看,这三个队列都是模块链表,第一个是按载入的先后顺序。第二个是按在虚拟空间中的位置,第三个是按初始化的顺序。

    第二个easy理解,可是第一个和第三个有什么差别呢?载入是先于初始化的,载入就是完毕虚拟空间的映射和与exe的链接。载入完毕后的DLL会挂入InInitializationOrderModuleList。进行初始化,初始化就是调用其DLLMain。能够看到的一点是InLoadOrderModuleList中有exe本身的模块,而InInitializationOrderModuleList中仅仅有exe依赖的DLL。(当然。这随着系统版本号在发生变化)

    我们要使用的是InInitializationOrderModuleList,挂入该链表中的为LDR_DATA_TABLE_ENTRY。也就是说。每一个载入的模块相应于一个LDR_DATA_TABLE_ENTRY,该结构例如以下:

    /*****************************************************************************/
    typedef struct _LDR_DATA_TABLE_ENTRY  
    {  
        LIST_ENTRY InLoadOrderLinks;  
        LIST_ENTRY InMemoryOrderLinks;  
        LIST_ENTRY InInitializationOrderLinks;  
        PVOID DllBase;  
        PVOID EntryPoint;  
        DWORD SizeOfImage;  
        UNICODE_STRING FullDllName;  
        UNICODE_STRING BaseDllName;  
        DWORD Flags;  
        WORD LoadCount;  
        WORD TlsIndex;  
        LIST_ENTRY HashLinks;  
        PVOID SectionPointer;  
        DWORD CheckSum;  
        DWORD TimeDateStamp;  
        PVOID LoadedImports;  
        PVOID EntryPointActivationContext;  
        PVOID PatchInformation;  
    }LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;  
    /*****************************************************************************/

    相同。在我的机器上为:
    这里写图片描写叙述
    前面三个链表相应于该结构挂入的三个链表,重点在于第四个成员DllBase,这是载入模块的基地址。因此,我们仅仅须要顺着InInitializationOrderModuleList链表找到kernel32.dll的PLDR_DATA_TABLE_ENTRY。然后通过其DllBase成员。就知道了kernel32.dll载入的地址。

    那么InInitializationOrderModuleList链表中哪一个kernel32.dll呢?最保险的方法是解析FullDllName成员,这样代码会比較复杂。实际上在特定版本号的系统中,动态库初始化的顺序是一定的。第一个为ntdll.dll,第二个就是kernel32.dll。Vista 以后第二个是kernelbase.dll。第三个是kernel32.dll。因此,能够避免解析FullDllName成员。

    如今。我们要找到进程的PEB结构地址,PEB结构保存于线程的TEB结构中的peb成员,而Windows系统中,寄存器fs总是指向当前线程的TEB。因此。获取kernel32.dll基地址的整个流程例如以下:

    这里写图片描写叙述
    图38

    写代码之前。先通过调试器顺着该顺序看一看,我用windbg载入的是example_1。输入:
    d fs:[0x30]查看当前peb的地址:

    这里写图片描写叙述
    图39

    地址为0x7ffda000。输入:!peb。验证一下:

    这里写图片描写叙述
    图40

    是相同的。

    输入: d 7ffda000+0x0c,查看PEB_LDR_DATA结构的地址:

    这里写图片描写叙述
    图41

    输入: d 00251ea0+0x1c,查看InInitializationOrderModuleList链表:

    这里写图片描写叙述
    图42

    先列一下LIST_ENTRY结构。Flink 指向下一个节点:

    /*****************************************************************************/
    typedef struct _LIST_ENTRY 
    {
         struct _LIST_ENTRY *Flink; 
         struct _LIST_ENTRY *Blink; 
    } LIST_ENTRY, *PLIST_ENTRY;
    /*****************************************************************************/

    因此。0x00251f58是第一个元素。输入:d 0x00251f58查看下面其内容:

    这里写图片描写叙述
    基地址为0x7c920000,可是右边显示为kernel32.dll???第一个元素不是ntdll.dll吗?

    来看看下一个元素:
    这里写图片描写叙述
    基地址为0x7c800000。显示为uer32.dll,看来是出了一些问题,输入!peb来看看:

    这里写图片描写叙述
    这里的基地址和名称相应才是对的。

    下面来写获取kernel32.dll基地址的代码:

    /*****************************************************************************/
    // example_8 获取kernel32.dll的基地址
    #include <stdio.h>
    
    // 获取kernel32.dll的基地址
    int get_kernel32_base()
    {
        __asm
        {
            mov eax, fs:[0x30]  // PEB
            mov eax, [eax+0x0c] // PEB->Ldr
            mov eax, [eax+0x1c] // PEB->Ldr.InInitializationOrderModuleList.Flink(指向第一个元素)
            mov eax, [eax]      // 指向第二个元素
            mov eax, [eax+0x08] // kernel32.dll基地址
        }
    }
    
    int main()
    {
        printf("0x%x
    ", get_kernel32_base());
    
        return 0;
    }
    /*****************************************************************************/

    结果例如以下:
    这里写图片描写叙述
    图43

    这里是一种方法,其他方法(包含Windows 7)请看:

    http://blog.harmonysecurity.com/2009_06_01_archive.html

  • 相关阅读:
    保持URL不变和数字验证
    centOS ftp key?
    本地环境测试二级域名
    linux 解决You don't have permission to access 问题
    php smarty section loop
    php header Cannot modify header information headers already sent by ... 解决办法
    linux部分命令
    Linux 里面的文件操作权限说明
    用IT网络和安全专业人士视角来裁剪云的定义
    SQL Server 2008 R2炫酷报表"智"作有方
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7262655.html
Copyright © 2011-2022 走看看