其实在大部分的函数都会遵循我下面要说的这个过程,因为我们所熟知的大部分函数都是在Kernel32.dll、User32.dll、GDI32.dll等系统模块里,所以基本上都会符合我说的这个过程。首先我们来举个例子来说明一下,比如我们的程序中调用的CreateFile这个函数。
int _tmain(int argc, _TCHAR* argv[])
{
//_asm int 3;
CreateFileW(L"D:\\T\\Test.exe", GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
return 0;
}
当我们在调用 这个函数的时候,你以为到了这些个系统模块中就完成了函数的调用,实则你错了,这些函数的调用全部来自系统内核的调用,Ring3和Ring0之间会有一扇门,通过了这个门你就可以到达Ring0,然后可以为所欲为,内核空间是所有进程共用的,所以没有属于谁的说法。然而我们我们一般的调试器都是跑在Ring3,你会发现有时你想跟一个函数,一直跟下去,但是却不能跟到头,因为在某处,程序本身已经进内核执行完都回来了,然后eax都有值了你都不知道发生了什么。下面我们来看下这个CreateFile函数,试着跟下它……抓紧它的手,不放开(捂脸笑)
这里就是main函数里的CreateFile函数了,然后我们就一步一步跟进去
这里需要说几句,下图中会发现汇编代码都比较像,是因为这里集合Windows各个模块的函数,每个调用号代表了一个函数,当前我们选中的这一行就是CreateFile函数。
这里我们通过ARK工具PCHunter来查看下系统中对应的函数序号以及函数名称是否一样。
地址:77C300CF 我们通过这个call 进入这个函数发现只有一条jmp指令了
其实这里就是真正进入Ring0的入口了,但是OD却解析成了远跳指令,这里如果使用Windbg分析的话,指令就是sysenter了,在这里cpu会将MSR寄存器中的值直接写入相关寄存器,这种调用方式叫做快速调用。MSR 176号的位置保存的就是Ring0的函数地址,过去之后会根据之前eax保存的调用号来当下标索引对照着SSDT表(系统描述符表)找到函数地址,然后进行调用。
好了,到这里就分析结束了,小伙伴们自己也可以试着跟着我写的步骤进入OD尝试跟下你想跟的函数,Ring3能看到的就只有这些了,进入Ring0之后可以使用微软提供的调试器Windbg跟着分析。