0x01 找kernel32基地址的方法一般有三种:

暴力搜索法、异常处理链表搜索法、PEB法。

0x02 基本原理

暴力搜索法是最早的动态查找kernel32基地址的方法。它的原理是几乎所有的win32可执行文件(pe格式文件)运行的时候都加载kernel32.dll,可执行文件进入入口点执行后esp
存放的一般是Kernel32.DLL 中的某个地址,所以沿着这个地址向上查找就可以找到kernel32的基地址。
那么如何知道我们找到的地址是kernel32的基地址呢?
因为kernel32.dll也是标准的pe结构文件,pe结构文件的开始是IMAGE_DOS_HEADER结构,IMAGE_DOS_HEADER结构的第一个字段是e_magic,它的值为’MZ’用于证明这是DOS兼容的
文件类型,所以如果我们找到的地址所指向的字符串为’MZ’,那么我们可以确信这是kernel32的基地址

所谓异常处理链表就是系统提供的处理异常的机制,当系统
遇到一个不知道如何处理的异常时就会查找异常处理链表,找到对应的异常处理程序,把保存的处理程序地址赋给eip,并执行处理程序,避免系统崩溃,异常处理链表的最后一项
是默认异常处理函数UnhandledExceptionFilter,因为UnhandledExceptionFilter在kernel32中,所以从UNhandledExceptionFilter地址向上搜索即可找到kernel32的基地址

PEB法

TEB结构

 //
 // Thread Environment Block (TEB)
 //
 typedef struct _TEB
 {
     NT_TIB Tib;                             /* 00h */
     PVOID EnvironmentPointer;               /* 1Ch */
     CLIENT_ID Cid;                          /* 20h */
     PVOID ActiveRpcHandle;                  /* 28h */
     PVOID ThreadLocalStoragePointer;        /* 2Ch */
     struct _PEB *ProcessEnvironmentBlock;   /* 30h */
     ULONG LastErrorValue;                   /* 34h */
     ULONG CountOfOwnedCriticalSections;     /* 38h */
     PVOID CsrClientThread;                  /* 3Ch */
     struct _W32THREAD* Win32ThreadInfo;     /* 40h */
     ULONG User32Reserved[0x1A];             /* 44h */
     ULONG UserReserved[];                  /* ACh */
     PVOID WOW32Reserved;                    /* C0h */
     LCID CurrentLocale;                     /* C4h */
     ULONG FpSoftwareStatusRegister;         /* C8h */
     PVOID SystemReserved1[0x36];            /* CCh */
     LONG ExceptionCode;                     /* 1A4h */
     struct _ACTIVATION_CONTEXT_STACK *ActivationContextStackPointer; /* 1A8h */
     UCHAR SpareBytes1[0x28];                /* 1ACh */
     GDI_TEB_BATCH GdiTebBatch;              /* 1D4h */
     CLIENT_ID RealClientId;                 /* 6B4h */
     PVOID GdiCachedProcessHandle;           /* 6BCh */
     ULONG GdiClientPID;                     /* 6C0h */
     ULONG GdiClientTID;                     /* 6C4h */
     PVOID GdiThreadLocalInfo;               /* 6C8h */
     ULONG Win32ClientInfo[];              /* 6CCh */
     PVOID glDispatchTable[0xE9];            /* 7C4h */
     ULONG glReserved1[0x1D];                /* B68h */
     PVOID glReserved2;                      /* BDCh */
     PVOID glSectionInfo;                    /* BE0h */
     PVOID glSection;                        /* BE4h */
     PVOID glTable;                          /* BE8h */
     PVOID glCurrentRC;                      /* BECh */
     PVOID glContext;                        /* BF0h */
     NTSTATUS LastStatusValue;               /* BF4h */
     UNICODE_STRING StaticUnicodeString;     /* BF8h */
     WCHAR StaticUnicodeBuffer[0x105];       /* C00h */
     PVOID DeallocationStack;                /* E0Ch */
     PVOID TlsSlots[0x40];                   /* E10h */
     LIST_ENTRY TlsLinks;                    /* F10h */
     PVOID Vdm;                              /* F18h */
     PVOID ReservedForNtRpc;                 /* F1Ch */
     PVOID DbgSsReserved[0x2];               /* F20h */
     ULONG HardErrorDisabled;                /* F28h */
     PVOID Instrumentation[];              /* F2Ch */
     PVOID SubProcessTag;                    /* F64h */
     PVOID EtwTraceData;                     /* F68h */
     PVOID WinSockData;                      /* F6Ch */
     ULONG GdiBatchCount;                    /* F70h */
     BOOLEAN InDbgPrint;                     /* F74h */
     BOOLEAN FreeStackOnTermination;         /* F75h */
     BOOLEAN HasFiberData;                   /* F76h */
     UCHAR IdealProcessor;                   /* F77h */
     ULONG GuaranteedStackBytes;             /* F78h */
     PVOID ReservedForPerf;                  /* F7Ch */
     PVOID ReservedForOle;                   /* F80h */
     ULONG WaitingOnLoaderLock;              /* F84h */
     ULONG SparePointer1;                    /* F88h */
     ULONG SoftPatchPtr1;                    /* F8Ch */
     ULONG SoftPatchPtr2;                    /* F90h */
     PVOID *TlsExpansionSlots;               /* F94h */
     ULONG ImpersionationLocale;             /* F98h */
     ULONG IsImpersonating;                  /* F9Ch */
     PVOID NlsCache;                         /* FA0h */
     PVOID pShimData;                        /* FA4h */
     ULONG HeapVirualAffinity;               /* FA8h */
     PVOID CurrentTransactionHandle;         /* FACh */
     PTEB_ACTIVE_FRAME ActiveFrame;          /* FB0h */
     PVOID FlsData;                          /* FB4h */
     UCHAR SafeThunkCall;                    /* FB8h */
     UCHAR BooleanSpare[];                  /* FB9h */
 } TEB, *PTEB; 

PEB结构

 typedef struct _PEB
 {
     UCHAR InheritedAddressSpace; // 00h
     UCHAR ReadImageFileExecOptions; // 01h
     UCHAR BeingDebugged; // 02h
     UCHAR Spare; // 03h
     PVOID Mutant; // 04h
     PVOID ImageBaseAddress; // 08h
     PPEB_LDR_DATA Ldr; // 0Ch
     PRTL_USER_PROCESS_PARAMETERS ProcessParameters; // 10h
     PVOID SubSystemData; // 14h
     PVOID ProcessHeap; // 18h
     PVOID FastPebLock; // 1Ch
     PPEBLOCKROUTINE FastPebLockRoutine; // 20h
     PPEBLOCKROUTINE FastPebUnlockRoutine; // 24h
     ULONG EnvironmentUpdateCount; // 28h
     PVOID* KernelCallbackTable; // 2Ch
     PVOID EventLogSection; // 30h
     PVOID EventLog; // 34h
     PPEB_FREE_BLOCK FreeList; // 38h
     ULONG TlsExpansionCounter; // 3Ch
     PVOID TlsBitmap; // 40h
     ULONG TlsBitmapBits[0x2]; // 44h
     PVOID ReadOnlySharedMemoryBase; // 4Ch
     PVOID ReadOnlySharedMemoryHeap; // 50h
     PVOID* ReadOnlyStaticServerData; // 54h
     PVOID AnsiCodePageData; // 58h
     PVOID OemCodePageData; // 5Ch
     PVOID UnicodeCaseTableData; // 60h
     ULONG NumberOfProcessors; // 64h
     ULONG NtGlobalFlag; // 68h
     UCHAR Spare2[0x4]; // 6Ch
     LARGE_INTEGER CriticalSectionTimeout; // 70h
     ULONG HeapSegmentReserve; // 78h
     ULONG HeapSegmentCommit; // 7Ch
     ULONG HeapDeCommitTotalFreeThreshold; // 80h
     ULONG HeapDeCommitFreeBlockThreshold; // 84h
     ULONG NumberOfHeaps; // 88h
     ULONG MaximumNumberOfHeaps; // 8Ch
     PVOID** ProcessHeaps; // 90h
     PVOID GdiSharedHandleTable; // 94h
     PVOID ProcessStarterHelper; // 98h
     PVOID GdiDCAttributeList; // 9Ch
     PVOID LoaderLock; // A0h
     ULONG OSMajorVersion; // A4h
     ULONG OSMinorVersion; // A8h
     ULONG OSBuildNumber; // ACh
     ULONG OSPlatformId; // B0h
     ULONG ImageSubSystem; // B4h
     ULONG ImageSubSystemMajorVersion; // B8h
     ULONG ImageSubSystemMinorVersion; // C0h
     ULONG GdiHandleBuffer[0x22]; // C4h
     PVOID ProcessWindowStation; // ???
 } PEB, *PPEB;

原理:在NT内核系统中fs寄存器指向TEB结构,TEB+0x30处指向PEB结构,PEB+0x0c处指向PEB_LDR_DATA结构,

PEB_LDR_DATA+0x1c处存放一些动态链接库地址,第一个指向ntdl.dll,第二个就是kernel32.dll的基地址了

0x03 验证以上办法可行性

现在我们就来研究下第一中方法暴力搜索法

http://blog.csdn.net/syf442/article/details/4383254(更详细的介绍)

ps:按照上面文章介绍不会触发 非法访问问题,实验证明(环境xp sp2 + vc++6.0) 确实有 非法访问的 异常

 #include "stdafx.h"
 #include <stdio.h>

 int main()
 {

 _asm { jmp Start }
 int ieax;

 _asm{
 Start:

 GetKernelBase:                    ;查找 kernel地址
         mov eax,7c800000h        ;因为有非法访问我直接把我本机的kerne32.dll地址(7c800000h) 给eax 就可以了

 Compare:
         cmp eax,80000000h
         jl    SearchFinal
         cmp word ptr[eax],'ZM'
         je FindedKernelBase
         add    eax,010000h
         jmp Compare

 }
 FindedKernelBase:
 {
         _asm{ mov ieax,eax}
         printf("kernel addr offset %x \n",ieax);
         ;
 }
 SearchFinal    :
 {            //;查找结束
         printf("find kernel faild \n ");
         ;
 }
     ;
 }

我刚开始按照老罗的思路,从栈顶向下搜索,有问题

后来我就从8000000h搜索至70000000h处

发现有非法访问

为了确定我的发现

我从从7000000h搜索至80000000h处

还是有非法访问

那我直接把我电脑的kernel32.dll地址 替换 7000000h 为7c800000h

直接可以了

论证 暴力搜索法 不是太通用呀

第二中办法 (SEH)异常处理链表搜索法

其中要先补习下基础知识

异常处理链表末端的处理结构体是系统最后为异常准备的处理(其中的下一个结构指针prev 为-1),就是咱们经常遇到的程序崩溃的提示。其地址是在kernel32 内存空间内部,我们只要找到最后的异常处理结构体,那么我们从

这个地址找下去一定能找到 ‘MZ’标志(kernel32的地址);

其中SEH链表位置:fs:[0]->线程信息块TIB,TIB.ExceptionList->SEH链表

 nt!_NT_TIB
    +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD            ;SEH链表头
    +0x004 StackBase        : Ptr32 Void
    +0x008 StackLimit       : Ptr32 Void
    +0x00c SubSystemTib     : Ptr32 Void
    +0x010 FiberData        : Ptr32 Void
    +0x010 Version          : Uint4B
    +0x014 ArbitraryUserPointer : Ptr32 Void
    +0x018 Self             : Ptr32 _NT_TIB
 链表节点

 _EXCEPTION_REGISTRATION struc

     prev           dd ?                   ;下一个_EXCEPTION_REGISTRATION结构

     handler       dd ?                   ;异常处理函数地址

 _EXCEPTION_REGISTRATION ends
 #include <stdio.h>
 #include <windows.h>
 int main()
 {
  __asm
     {  

         mov edx, fs:[]     // 获得EXCEPTION_REGISTRATION结构地址
 Next:
         inc dword ptr [edx] // 将prev+1,如果是-1经过+1后等于0 (证明找到了 SEH链表的最后一项,也就达到了kernel的内存空间中了)                   // 其中第一次时:fs:[0]->线程信息块TIB,TIB.ExceptionList->SEH链表
         jz Krnl
         dec dword ptr [edx] // 不为-1,还原
         mov edx, [edx]      // 获得prev指向的地址
         jmp Next  

 Krnl:
         dec dword ptr [edx] // 恢复
         mov edx, [edx + ]  // 获得handle指向的地址  

 Looop:
         cmp word ptr [edx], 'ZM'
         jz IsPe
         dec edx
         xor dx, dx
         jmp Looop  

 IsPe:
         mov eax, dword ptr [edx + 3ch]
         cmp word ptr [edx + eax], 'EP'
         jnz Next
         mov dwKrnlAddr, edx
     }
     printf(TEXT("Kernel32.dll address: %x\r\n"), dwKrnlAddr);
     printf(TEXT("GetModuleHandle Kernel32.dll address: %x\r\n"),
     GetModuleHandle(TEXT("kernel32.dll")));
     printf(TEXT("LoadLibrary Kernel32.dll address: %x\r\n"),
     LoadLibrary(TEXT("kernel32.dll")));
     ;
 }

          xp sp2 的运行图(圆满的达到目标)

      win7 x64 sp1 的运行结构(其中下边使用DEPENDS.EXE发现的 DLL的基址)目测没有达到预期目标,难道是win7有什么猫腻,下小节动态跟踪下

但是论证了下发现此办法在xp sp2上 可以达到目的,而win7 x64 sp1 目测没有达到目的

进一步验证 SEH异常链表搜索法 在 win7上失败的原因

动态跟踪了下发现确实找到了MZ的标志,也验证存在PE标志,但是找的和 GetModuleHandle 、LoadLibrary 获取到的不对

据推测可能是 异常链表最后一项的系统处理 (在win7 下)不再kernel32内存空间中,在其他dll内存空间中。。。

win7下的 异常链表最后一项的系统处理  在ADVAPI32地址空间下(或许这样把)

接下来 我们实验 第三种办法PEB法

基础知识必须要学习点,其中TEB和PEB结构看上面。

原理:在NT内核系统中fs寄存器指向TEB结构,TEB+0x30处指向PEB结构,PEB+0x0c处指向PEB_LDR_DATA结构,

PEB_LDR_DATA+0x1c处存放一些动态链接库地址,第一个指向ntdl.dll,第二个就是kernel32.dll的基地址了

我先尝试这写下汇编代码这次就直接在win7上调试(很久前,我调试过PEB找kernel32地址的代码,确实可行)

下面代码通过PEB获取得到了kernel32地址,通过函数表 得到了 GetProcAddress函数地址,通过此函数地址

获取Beep()函数地址,来证明 win7下 是可行的。。。

    int    (*pv)(HINSTANCE,char*);
    //pv = GetProcAdr;
    //pv = GetProcAdr;
    DWORD pBeep = ;
    DWORD pGetProcAddress = ;
    DWORD pKernel32 =;

    HINSTANCE hK = GetModuleHandle("kernel32.dll");
    //Beep
    printf(" Beep is %x \n",GetProcAddress(hK,"Beep"));

    _asm
    {
        push eax
            push esi
            push edx
            push ebp

            push esp

            sub esp,400h

            mov eax, fs:0x30 ;PEB的地址
            mov eax, [eax + 0x0c] ;Ldr的地址
            mov esi, [eax + 0x1c] ;Flink地址
            lodsd
            mov eax, [eax + 0x08] ;eax就是kernel32.dll的地址
            mov pKernel32,eax
            mov ebp,eax
            mov eax, [ebp+3Ch] ;eax = PE首部
            mov edx,[ebp+eax+78h]
        add edx,ebp ;edx = 引出表地址
            mov ecx , [edx+18h] ;ecx = 输出函数的个数
            mov ebx,[edx+20h]
        add ebx, ebp ;ebx =函数名地址,AddressOfName
search:
        dec ecx
            mov esi,[ebx+ecx*]
        add esi,ebp ;依次找每个函数名称
            ;GetProcAddress
            mov eax,0x50746547
            cmp [esi], eax; 'PteG'
            jne search
            mov eax,0x41636f72
            cmp [esi+],eax; 'Acor'
            jne search
            ;如果是GetProcA,表示找到了
            mov ebx,[edx+24h]
        add ebx,ebp ;ebx = 序号数组地址,AddressOf
            mov cx,[ebx+ecx*] ;ecx = 计算出的序号值
            mov ebx,[edx+1Ch]
        add ebx,ebp ;ebx=函数地址的起始位置,AddressOfFunction
            mov eax,[ebx+ecx*]
        add eax,ebp ;利用序号值,得到出GetProcAddress的地址 

            add esp,400h
            pop esp
            pop ebp
            pop edx
            pop esi

            //mov ebx,[eax + 3ch ]
            //mov ebx,[eax + ebx + 78h]
            //add ebx,eax
            //mov ebx,[ebx+20h]
            //add ebx,eax

            mov pGetProcAddress,eax
            mov pv,eax
            pop eax 

            // yan zheng han GetAddress 正确性
            // beep
            //sub esp,90h

            //push 0x70656562
            //push hK
            //call pv

            //add esp,90h
            ////add esp,8h
            //mov pBeep,eax
    }
    int a = (pv)(hK,"Beep") ;

    printf(" Beep is %x \n", a   );

    printf("kernel32 addr is %x , PEB get GetProcAddress addr is %x \n",pKernel32,pGetProcAddress);

    printf("kernel32 addr is %x , \r\n GetProcAddress() get GetProcAddress addr is %x \n",GetModuleHandle("kernel32.dll"),GetProcAddress(GetModuleHandle("kernel32.dll"),"GetProcAddress"));

(以上代码 在 int a = (pv)(hK,"Beep") ; 存在 chkesp 提示,不知如何平衡堆栈,调试了好久 还请 高人指点 )

虽然在 win7 搜索得到的GetProcAddress地址 和 用 GetProcAddress()函数获取得到的GetProcAddress地址不同;但是,通过搜索得到的 GetProcAddress地址 调用这个地址 获取到的Beep()函数都是相同的,Ollydby动态调试,也证实了以上结论!

文章到这里就算结束了!!!!

旧书重温:0day2【2】 实验:三种获取kernel32.dll基址的方法的更多相关文章

  1. [转]SQL三种获取自增长的ID方法

     最新更新请访问: http://denghejun.github.io   SQL SERVER中的三种获得自增长ID的方法  这个功能比较常用,所以记下来以防自己忘掉. SCOPE_IDENTIT ...

  2. Request三种获取数据的方式

    今天在做ajax请求后台代码时,发现ajax的方法都对,但就是请求不了后台代码,后来在同事帮助下才发现前台定义了两个相同参数导致请求出错. 下面记录一下request三种获取数据的方式: 1. Req ...

  3. Js之Dom学习-三种获取页面元素的方式、事件、innerText和innerHTML的异同

    一.三种获取页面元素的方式: getElementById:通过id来获取 <body> <input type="text" value="请输入一个 ...

  4. 三种dedecms调用相关文章的方法

    在文章的末尾或侧边栏添加相关文章可以提高用户的黏度,提高pv,增加se的好印象(哈哈),那么dedecms如何调用相关文章呢?有三种方法可以实现. 第一种dedecms调用相关文章的方法,用默认的li ...

  5. MySQL、SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法

    在这里主要讲解一下MySQL.SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法. 可能会有人说这些网上都有,但我的主要目的是把这些知识通过我实际的应 ...

  6. 三种计算c#程序运行时间的方法

    三种计算c#程序运行时间的方法 第一种: 利用 System.DateTime.Now // example1: System.DateTime.Now method DateTime dt1 = S ...

  7. jQuery 的三种获取值的方式

    本节内容主要介绍的是如何使用jQuery中的.html(),.text()和.val()三种方法,用于读取,修改元素的html结构,元素的文本内容,以及表单元素的value值的方法.jQuery中为我 ...

  8. jQuery ui autocomplete下拉列表样式失效解决,三种获取数据源方式,

    jQuery有很多很多的已经实现,很漂亮的插件,autocomplete就是其中之一.jQuery ui autocomplete主要支持字符串Array.JSON两种数据格式,jQuery ui b ...

  9. nodejs Express 4.x req.body req.query req.params 三种获取参数的方法

    第一种情况:http://localhost:3000/1,我们可以用req.params.(应该是跟路由有关,待) 第二种情况:http://localhost:3000/?id=1,用req.qu ...

随机推荐

  1. YUV420查表法高效、无失真的转换为RGB32格式

    YUV格式有两大类:planar和packed.planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V,这里所讲述的就是这中存储格式的:packed的YUV ...

  2. netfilter-IPv4实现框架分析(一)

    基于Linux-2.6.30版本,具体实现net\ipv4\netfilter目录下,入口文件为net\ipv4\netfilter\iptable_filter.c,入口/出口函数为模块的init函 ...

  3. POJ2528+线段树

    见代码. /* 线段树+Lazy 题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度. 现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW. 后贴的海 ...

  4. JavaScript动态操作style

    1.易错:修改元素的样式不是设置class属性,而是className属性.class是JS的一个保留关键字. 2.易错:单独修改样式的属性使用"style.属性名"3.注意在cs ...

  5. prestashop二次开发 笔记(支付插件)

    //主函数 public function __construct() { $this->name = 'CilPay';    //模块名称         $this->display ...

  6. sql2008存储过程解密。

    今天有一个同事在做一个项目的时候,因为现在公司不跟某一家公司合作.有一些sql的存储过程是加密,现在想打开那些存储过程来解密.故查看了一些资料终于解密成功.步骤如下: 1.需要开始DAC连接. 1.1 ...

  7. Redhat Linux挂载NTFS格式的移动硬盘

    Redhat Linux挂载NTFS格式的移动硬盘 1. 选择下载ntfs-3g的源码包或rpm包 http://www.tuxera.com/community/open-source-ntfs-3 ...

  8. Python的下载和安装

    一.下载(官方下载地址) 地址:https://www.python.org/downloads/ 我的是window7系统 二.安装详细过程 在选择安装组件的一步时,勾上所有的组件: 特别要注意选上 ...

  9. mac上搭建appium环境过程以及遇到的问题

    Mac环境安装appium 一.Java环境 下载java sdk http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downl ...

  10. ubuntu小技巧(不定期更新)

    1.gedit打开windows保存的txt出现乱码 默认情况下,用ubuntu打开windows保存含有中文的txt文件时会出现乱码. 只需在终端运行以下两条命令则可解决. gsettings se ...