| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 9343 人关注过本帖, 1 人收藏
标题:病毒技术二:获取kernel32.dll基址
取消只看楼主 加入收藏
AXRZ
Rank: 2
等 级:论坛游民
威 望:5
帖 子:48
专家分:84
注 册:2016-3-23
收藏(1)
 问题点数:0 回复次数:1 
病毒技术二:获取kernel32.dll基址
--------为何要动态取得kernel32.dll基址--------

“取得kernel32.dll的基址有何用?直接链接不就行了。”想必不少人会这么问;当然,如果你不想你的病毒兼容各个Windows平台,这一步是不需要的。
我们都知道,链接器动态链接的原理其实是将操作系统DLL中的API地址导入到我们的程序中,因为不同版本的Windows上DLL的基址会有所不同,所以你在WIN7上导入的"GetProcAddress"不一定能在WIN10上工作(因为地址不一样)。获取了kernel32.dll基址后就可以获取LoadLibrary()和GetProcAddress()的地址,有了它们之后我们之后就不用大费周章的去找API了。


--------取得kernel32.dll基址的方法--------

取得kernel32.dll基址的办法很多,这里介绍很简单的一种(但是背后的原理很繁琐),下面是取得其基址的一个子过程代码:
;NASM版本:
GETKERNEL32ADDR:
    XCHG EAX,EBX
    MOV EBX,[FS:30H]                ;从TIB(Thread Information Block)中取得PEB(Process Environment Block)的地址
    MOV EBX,[EBX+0CH]               ;从PEB中取得LDR类的基址
    MOV EBX,[EBX+14H]               ;从LDR中获取InMemoryOrderModuleList.Flink的地址(入口1,属于主进程)
    MOV EBX,[EBX]                   ;从InMemoryOrderModuleList.Flink取得InMemoryOrderModuleList.Flink.Flink的地址(入口2,属于ntdll.dll)
    MOV EBX,[EBX]                   ;同上,取得InMemoryOrderModuleList.Flink.Flink.Flink的地址(入口3,属于kernel32.dll)
    MOV EBX,[EBX+10H]               ;通过InMemoryOrderModuleList.Flink.Flink.Flink提供的_LDR_DATA_TABLE_ENTRY,再从中最终获取入口3的基址,也就是kernel32.dll的基址了
    XCHG EAX,EBX                    ;此过程的返回kernel32.dll的基址,存于EAX寄存器中
    RETN

;MASM版本:
GETKERNEL32ADDR PROC
    XCHG EAX,EBX
    MOV EBX,FS:[30H]                ;从TIB(Thread Information Block)中取得PEB(Process Environment Block)的地址
    MOV EBX,[EBX+0CH]               ;从PEB中取得LDR类的基址
    MOV EBX,[EBX+14H]               ;从LDR中获取InMemoryOrderModuleList.Flink的地址(入口1,属于主进程)
    MOV EBX,[EBX]                   ;从InMemoryOrderModuleList.Flink取得InMemoryOrderModuleList.Flink.Flink的地址(入口2,属于ntdll.dll)
    MOV EBX,[EBX]                   ;同上,取得InMemoryOrderModuleList.Flink.Flink.Flink的地址(入口3,属于kernel32.dll)
    MOV EBX,[EBX+10H]               ;通过InMemoryOrderModuleList.Flink.Flink.Flink提供的_LDR_DATA_TABLE_ENTRY,再从中最终获取入口3的基址,也就是kernel32.dll的基址了
    XCHG EAX,EBX                    ;此过程的返回kernel32.dll的基址,存于EAX寄存器中
    RETN
GETKERNEL32ADDR ENDP

这段代码可以通过C语言中用以下表达式验证:
unsigned int Kernel32Address = (unsigned int)GetModuleHandleA("kernel32.dll");

--------以上代码取得kernel32.dll基址的原理--------

以下为PEB的结构:
typedef struct _PEB {
  BYTE                          Reserved1[2];           //2字节
  BYTE                          BeingDebugged;          //1字节
  BYTE                          Reserved2[1];           //1字节
  PVOID                         Reserved3[2];           //8字节
  PPEB_LDR_DATA                 Ldr;                    //LDR的地址为{此类地址 + 2 + 1 + 1 + 8} = {此类地址 + 12(0CH)},前面代码中MOV EBX,[EBX+0CH]的原理
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;

------------------------------------------------------------------------------------------------------------
以下为LDR的结构:
typedef struct _PEB_LDR_DATA {
  BYTE       Reserved1[8];                               //8字节
  PVOID      Reserved2[3];                               //12字节
  LIST_ENTRY InMemoryOrderModuleList;                    //InMemoryOrderModuleList中有两个LIST_ENTRY指针,其地址为{此类地址 + 8 + 12} = {此类地址 + 20(14H)},前面代码中MOV EBX,[EBX+14H]的原理
} PEB_LDR_DATA, *PPEB_LDR_DATA;

以下为InMemoryOrderModuleList的结构:
typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;                            //这两个类相互链接,指向LDR_DATA_TABLE_ENTRY类的地址(指针)
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

以下为LDR_DATA_TABLE_ENTRY的结构:
typedef struct
{
    LIST_ENTRY InMemoryOrderLinks;                        //上面的那个类,8字节
    LIST_ENTRY InInitializationOrderLinks;                //8字节
    PVOID DllBase;                                        //DLL基址,我们想要的东西,其地址为{此类地址 + 8 + 8} = {此类地址 + 16(10H)},前面代码中MOV EBX,[EBX+10H]的原理
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    WORD LoadCount;
    WORD TlsIndex;
    union
    {
        LIST_ENTRY HashLinks;
        struct
        {
            PVOID SectionPointer;
            ULONG CheckSum;
        };
    };
    union
    {
        ULONG TimeDateStamp;
        PVOID LoadedImports;
    };
    _ACTIVATION_CONTEXT * EntryPointActivationContext;
    PVOID PatchInformation;
    LIST_ENTRY ForwarderLinks;
    LIST_ENTRY ServiceTagLinks;
    LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY_, *PLDR_DATA_TABLE_ENTRY_;

PEB的详细信息:https://msdn.(v=vs.85).aspx
PEB_LDR_DATA的详细信息:https://msdn.(v=vs.85).aspx


前面的章节:
病毒技术一:程序的重定位--http://bbs.bccn.net/thread-464424-1-1.html

[此贴子已经被作者于2016-5-29 05:15编辑过]

搜索更多相关主题的帖子: 动态 技术 操作系统 Windows 
2016-05-16 00:52
AXRZ
Rank: 2
等 级:论坛游民
威 望:5
帖 子:48
专家分:84
注 册:2016-3-23
收藏
得分:0 
回复 3楼 zhulei1978
正如楼上说的:
这两条指令虽然代码一样,生成的机器码也一样,但是实际操作是这样子的:
MOV EBX,[EBX]            ;这条指令的含义是用寄存器EBX中的值进行寻址;我们假设在执行这个代码是EBX为12345678H,那么执行完这个代码之后EBX将会是内存偏移地址12345789H中的值,我们假设其为24681012H
MOV EBX,[EBX]            ;意义同上;现在EBX为24681012H,这条指令将会把内存地址24681012H中的值移入EBX中

这相当于C语言的双重指针:
int *p;            //一个指针
int **p = &p;            //一个指向指针的指针
拿C来讲你就清楚了吧
2016-05-17 11:28
快速回复:病毒技术二:获取kernel32.dll基址
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.033521 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved