我是靠谱客的博主 热情发夹,最近开发中收集的这篇文章主要介绍kernel32基地址获得学习笔记第一种方法第二种方法:第三种方法:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题

第一种方法

通过线程初始化时, 获得esp堆栈指针中的ExitThread函数的地址,然后通过搜索获得kernel32.dll的基地址。

线程在被初始化的时,其堆栈指针指向ExitThread函数的地址,windows这样做是为了通过ret返回时来调用ExitThread地址。所以一般我们可以在我们主线程的起始位置(也就是
程序入口点处)通过获得堆栈指针中ExitThread函数(当然你要想创建一个线程时候获得也可以)

我们直接通过
mov  edx, [esp] ;获得堆栈指针中ExitThread地址到edx寄存器。因为ExitThread地址在kernel32.dll空间中,所以我们可以通过它往上搜索来获得基地址。

分析过kernel32.dll的朋友应该都知道kernel32.dll的块对齐值是00001000h, 并且一般DLL以1M为边界,所以我们可以通过10000h (64k) 作为跨度,这样可以增加搜索速度。我们如何确定这个地址是基地址,我们都知道我们判断这个地址的前两个字节是否是"MZ",然后定位到PE头结构,然后判断是否是"PE",如果这两个都符合的话则表示我们的地址则是基地址了.

注意,程序要用汇编编写,至少我不会用VC来内联编写,应为这个方法需要在程序的一开始就获取,而用VC编写的会有启动函数,也就是mainCRTStartup这些

代码如下:

	.386
	.model flat, stdcall
	option casemap:none
	
include windows.inc
include kernel32.inc
include user32.inc
includelib user32.lib
includelib kernel32.lib
	
	.const
szFormat	db 'kernel32.dll address is: %x', 0dh, 0ah, 0
szFormat1	db 'LoadLibrary kernel32.dll address is: %x', 0dh, 0ah, 0
szKrnl32	db 'kernel32.dll', 0

	.data?
hStdOut		dd ?
dwWriteBytes	dd ?
szBuffer	db 1024 (?)

	.code
	
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 获取字符串长度
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
GetStrLen proc _lpString

	mov edi, _lpString
	or ecx, 0ffffffffh	; ecx初值等于-1
	xor eax, eax
	repnz scasb		; 循环扫描,每循环执行一次,ecx-1,直到出现0为止,0也会减1
	; 一个公式(摘自《C++反汇编与逆向分析技术揭秘》P183):
	; ecx(终值) = ecx(初值) - (Len + 1)
	; ecx(终值) = -1 - (Len + 1) = -(Len + 2)    : 将-1代入公式
	; neg(ecx(终值)) = Len + 2    : neg为求补,ecx(终值) = -(Len + 2),求补后为正Len + 2
	; not(ecx(终值)) + 1 = Len + 2
	; not(ecx(终值)) = Len + 1
    ; Len = not(ecx(终值)) - 1
    not ecx			
	dec ecx
	mov eax, ecx
	ret
	
GetStrLen endp 

start:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 获取kernel32的基址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	mov edx, [esp]
Next:
	cmp word ptr [edx], 'ZM'       ; 因为读取后edx的内容是高地址在高位,所以需要倒过来写MZ和PE
	jz IsPe
	dec edx
	xor dx, dx
	jmp Next
	
IsPe:
	mov eax, [edx + 3ch]
	cmp word ptr [edx + eax], 'EP'
	jnz Next
	
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 将自己获取的和LoadLibrary获取的地址显示出来用于对比
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	invoke GetStdHandle, STD_OUTPUT_HANDLE
	mov hStdOut, eax
	
	invoke wsprintf, addr szBuffer, addr szFormat, edx
	invoke GetStrLen, addr szBuffer
	invoke WriteConsole, hStdOut, addr szBuffer, ecx, addr dwWriteBytes, NULL
	
	invoke LoadLibrary, addr szKrnl32
	invoke wsprintf, addr szBuffer, addr szFormat1, eax
	invoke GetStrLen, addr szBuffer
	invoke WriteConsole, hStdOut, addr szBuffer, eax, addr dwWriteBytes, NULL
	
	invoke CloseHandle, hStdOut
	invoke ExitProcess, NULL
	
end start

第二种方法:

Note:这个方法适用于XP, win7上获得是ntdll.dll的地址。

这个方法是遍历遍历seh异常链,然后获得EXCEPTION_REGISTRATION结构prev为-1的异常处理过程地址,这个异常处理过程地址是位于kernel32.dll,通过它搜索得到kernel32.dll的基地址。
搜索的方法在上面我已经说了,通过减去跨度,然后判断地址前两字节是否是"MZ",是的话,继续定位到PE头结构,然后判断前两个字节是否是"PE",不是的话继续减去跨度搜索。直到是为止。

  struct EXCEPTION_REGISTRATION 
        prev dd ?                       
        handler dd ?                   
  ends 

  遍历的方法也很简单,我们都知道[fs:0]的ExceptionList 指向EXCEPTION_REGISTRATION结构,所以通过[fs:0]获得EXCEPTION_REGISTRATION结构后,判断prev成员是否是-1,如果是的话则取

异常处理过程地址,然后进行搜索。

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD dwKrnlAddr = 0;

	__asm
	{
		mov edx, fs:[0]		// 获得EXCEPTION_REGISTRATION结构地址
Next:
		inc dword ptr [edx]	// 将prev+1,如果是-1为0
		jz Krnl
		dec dword ptr [edx]	// 不为-1,还原
		mov edx, [edx]		// 获得prev指向的地址
		jmp Next

Krnl:
		dec dword ptr [edx]	// 恢复
		mov edx, [edx + 4]	// 获得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
	}
	_tprintf(TEXT("Kernel32.dll address: %xrn"), dwKrnlAddr);
	_tprintf(TEXT("GetModuleHandle Kernel32.dll address: %xrn"), 
		GetModuleHandle(TEXT("kernel32.dll")));

	return 0;
}

第三种方法:

此方法是通过TEB获得PEB结构地址,然后再获得PEB_LDR_DATA结构地址,然后遍历模块列表,查找kernel32.dll模块的基地址。

  TEB是线程环境块(Thread Environment Block)结构, 我们的fs段选择子所对应的段指向TEB,也就是fs:[0]指向TEB.那么TEB的ProcessEnvironmentBlock结构成员指
向我们的PEB进程环境块结构(Process Environment Block),然后通过PEB结构来获得PEB_LDR_DATA。 接下来我们通过windbg来查看下相关结构。

我们首先来看下TEB结构,通过windbg的dt命令。

lkd> dt _TEB
nt!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : Ptr32 Void
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : Ptr32 Void
   +0x02c ThreadLocalStoragePointer : Ptr32 Void
   +0x030 ProcessEnvironmentBlock : Ptr32 _PEB

   ......省略


我们可以看到TEB结构的0x30偏移处存储的我们的PEB结构的地址。。

   然后接下来我们来看PEB结构。

lkd> dt _PEB
nt!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 SpareBool        : UChar
   +0x004 Mutant           : Ptr32 Void
   +0x008 ImageBaseAddress : Ptr32 Void
   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA
   ..........省略

我们可以看到PEB结构的0x0c偏移处存储的我们的_PEB_LDR_DATA结构地址。

然后我们再来查看 _PEB_LDR_DATA结构

lkd> dt _PEB_LDR_DATA
nt!_PEB_LDR_DATA
   +0x000 Length           : Uint4B
   +0x004 Initialized      : UChar
   +0x008 SsHandle         : Ptr32 Void
   +0x00c InLoadOrderModuleList : _LIST_ENTRY
   +0x014 InMemoryOrderModuleList : _LIST_ENTRY
   +0x01c InInitializationOrderModuleList : _LIST_ENTRY
   +0x024 EntryInProgress  : Ptr32 Void

我们看到这个结构中的模块立标有3个_LIST_ENTRY结构,它们分别是
InLoadOrderModuleList (加载顺序模块列表)
InMemoryOrderModuleList(内存顺序模块排列)
InInitializationOrderModuleList(初始化顺序模块列表)

然后我们继续查看这个结构。

nt!_LIST_ENTRY
   +0x000 Flink            : Ptr32 _LIST_ENTRY
   +0x004 Blink            : Ptr32 _LIST_ENTRY
  
这个结构我们可以看到它是一个双向链表,Flink表示从前往后, Blink表示从后往前。

并且这三个链表的结点是均是指向此结构

typedef struct _LDR_MODULE
{
    LIST_ENTRY        InLoadOrderModuleList;            // +0x00
    LIST_ENTRY        InMemoryOrderModuleList;          // +0x08
    LIST_ENTRY        InInitializationOrderModuleList;  // +0x10
    PVOID             BaseAddress;                      // +0x18
    PVOID             EntryPoint;                       // +0x1c
    ULONG             SizeOfImage;                      // +0x20
    UNICODE_STRING    FullDllName;                      // +0x24
    UNICODE_STRING    BaseDllName;                      // +0x2c
    ULONG             Flags;                            // +0x34
    SHORT             LoadCount;                        // +0x38
    SHORT             TlsIndex;                         // +0x3a
    LIST_ENTRY        HashTableEntry;                   // +0x3c
    ULONG             TimeDateStamp;                    // +0x44
                                                        // +0x48
} LDR_MODULE, *PLDR_MODULE;


我们一般取它的初始化顺序结构(InInitializationOrderModuleList)的Flink成员指向的_LDR_MODULE结构的BaseAddress成员则为我们需要的基地址,当然由于第一个是
ntdll,所以取第二个则为我们的Kernel32.dll。

注意,这里在Win7中为第3个, 第2个是kernelbase.dll,可以通过LDR_MODULE结构的BaseDllName比较dll名称后来获取,参见:

windows7平台下定位kernel32基址的方法

windows 7下的病毒感染

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD dwKrnlAddr = 0;

	__asm
	{
		mov edx, fs:[30h]		// 取得PEB
		mov edx, [edx + 0ch]	// PEB_LDR_DATA
		mov edx, [edx + 1ch]	// 获得InInitializationOrderModuleList.Flink指向的地址,也即指向第一个LDR_MODULE		         
        mov edx, [edx]		// 因为edx当前为InInitializationOrderModuleList
					// 而它的第一成员Flink又指向下一个LDR_MODULE, 所以直接读取就是下一个
		mov edx, [edx + 8h]
		mov dwKrnlAddr, edx
	}
	_tprintf(TEXT("Kernel32.dll address: %xrn"), dwKrnlAddr);
	_tprintf(TEXT("GetModuleHandle Kernel32.dll address: %xrn"), 
		GetModuleHandle(TEXT("kernel32.dll")));

	return 0;
}


最后

以上就是热情发夹为你收集整理的kernel32基地址获得学习笔记第一种方法第二种方法:第三种方法:的全部内容,希望文章能够帮你解决kernel32基地址获得学习笔记第一种方法第二种方法:第三种方法:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(29)

评论列表共有 0 条评论

立即
投稿
返回
顶部