首页
社区
课程
招聘
[旧帖] [原创]学习笔记--函数在内存中的定位 0.00雪花
发表于: 2011-11-21 08:43 2473

[旧帖] [原创]学习笔记--函数在内存中的定位 0.00雪花

2011-11-21 08:43
2473

// querySystemInfomation.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "windows.h"
#include "malloc.h"

/*发一篇学习心得,本人很菜,自学编程 ,学习点东西都很费力,希望大牛不要笑我
/最近学到内核编程遇到了很多直接强类型缓存区,譬如从SSDT中定位api,ZwQuerySystemInformation 等....
以前学asp.net没考虑过这些,当遇到这些问题时候,思路还是很模糊的,这些天,不断的遇到这样的操作,于是我就
写了下面这个练习,证明,在内存中数据的存取是靠基址 + 偏移,有了基地之 就可以通过偏移改PE文件,idt,ssdt等等操作
*/

typedef enum _class
{
        P_INFORMATION=1, //SYSTEM_PROCESS_INFORMATION
        M_INFORMATION, //SYSTEM_MODULE_INFORMATION
        T_INFORMATION //根据这个标志等下我们随意的一个偏移处写个函数放进去
}INFO_CLASS;

//进程结构
typedef struct _SYSTEM_PRCESS_INFORMATION
{
        UINT pid;
        char name[8];
}SYSTEM_PROCESS_INFORMATION,*PSYSTEM_PROCESS_INFORMATION;

//模块结构
typedef struct _SYSTEM_MODULE_INFORMATION
{
        DWORD addr;
        char name[8];
        int flag;
}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;

//假设这个函数在ssdt中 偏移为16 也就是 index = 4  ===>baseAddress + index * 4 得到这个 函数地址  
int add(int a,int b)
{
        return a+b;
}

#pragma pack(4)
PVOID QueryInfo(INFO_CLASS cls,PVOID buffer)
{
        //初始化,取一些信息,放在内存中,供查询使用
        UINT pid=1234; //取进程id
        DWORD pName = 0x4241 ;//取进程名字:ab --这里注意下字节序
        DWORD mName = 0x4443 ; //取模块名字:cd
        int flag = 888; //取模块标志
        DWORD addr = 0xff; //取模块地址
        PVOID functionAddr = (PVOID)add; //取函数地址
       

        //下面我不用变量写入,直接用汇编写内存,避免变量概念的干扰
        switch(cls)
        {
        case P_INFORMATION:
                _asm
                {
                        //这里写进程id 和进程名 pName
                        mov eax,buffer
                        mov ebx,pid
                        mov [eax],ebx
                        mov ebx,pName
                        mov [eax+4],ebx
                }
               
                break;
        case M_INFORMATION:
        _asm
                {
                        //这里写模块地址addr,模块名字mName,模块标志flag
                        mov eax,buffer
                        mov ebx,addr
                        mov [eax],ebx
                        mov ebx,mName
                        mov [eax+4],ebx
                        mov ebx,flag
                        mov [eax+12],ebx

                }
                break;
        case T_INFORMATION:
                _asm
                {
                        //我们把Add函数存在ssdt中,偏移16
                        mov eax,buffer
                        mov ebx,functionAddr
                        mov [eax+16],ebx
                }
                break;
        }
        return buffer;
}
#pragma pack()

int _tmain(int argc, _TCHAR* argv[])
{

        PVOID buffer = malloc(36);

////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //读取一下进程信息
        PVOID baseAddress = QueryInfo(P_INFORMATION,buffer);
        if(baseAddress == NULL)
        {
                goto error;
        }
        PSYSTEM_PROCESS_INFORMATION pMessage = (PSYSTEM_PROCESS_INFORMATION)baseAddress;
        printf("|查询进程信息pid:%d -- pName:%s\n|",pMessage->pid,pMessage->name);

////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //读取一下模块信息
        baseAddress = QueryInfo(M_INFORMATION,buffer);
        if(baseAddress == NULL)
        {
                goto error;
        }
        PSYSTEM_MODULE_INFORMATION mMessage = (PSYSTEM_MODULE_INFORMATION)baseAddress;
        printf("|查询模块信息addr:0x%x -- mName:%s\--flag:%d\n|",mMessage->addr,mMessage->name,mMessage->flag);
       
////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //读取下偏移为16那里的函数
        typedef  int (*funs)(int a,int b);
        funs add;
        baseAddress = QueryInfo(T_INFORMATION,buffer);
        if(baseAddress == NULL)
        {
                goto error;
        }
        PVOID fMessage = baseAddress;       
        _asm
        {
                mov eax,fMessage
                mov eax,[eax+16]
                mov add,eax
        }
        int c =  add(50,20);
        printf("add函数结果:%d\n",c);
        //譬如说SSDT中偏移为16的地方存了一个函数入口地址 add(0x45645678)
        //现在我们就可以typedef void (*funs)()
        //funs f = (fun)[baseAddress+16]
        //f();
        //或者修改函数地址,这里要注意内存写保护的问题,和大小问题
        //(*(ULONG *)(baseAddress+16)) = myfunc;

        delete buffer;
        return 0;
error:
        printf("读取内存失败\n");
        delete buffer;
        return -1;
}
//系统的那个ZwQuerySystemInformation肯定比这个复杂很多,但是我感觉原理该差不多了,
//写完之后,感觉自己更加清晰了,可以很轻松的用KeServiecDescriptorTable + index *4 等去定位一些东西了.
//希望对那些和我一样菜的,还不是很明白的人能有所帮助,以后遇到譬如KeServiecDescriptorTable + index*4 ,ZwQuerySystemInformation 这样的东西不感到恐惧.
//2点了,睡觉。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 6
支持
分享
最新回复 (1)
雪    币: 364
活跃值: (91)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
顶下! 呵呵!
2011-11-21 10:06
0
游客
登录 | 注册 方可回帖
返回
//