-
-
[原创]奇怪的驱动全局变量初始化问题
-
发表于:
2013-3-7 12:56
7444
-
发现问题的过程是这样的:
为了保护驱动文件, 我做了一个PE结构变形与内存装载驱动的东西, 但是弄完之后使用过程中出现了很莫名奇怪的问题
期间苦逼的跟踪调试过程就不说了, 最终定位到的问题竟然跟全局变量的初始化有关系(当然, 通过系统的常规方法装载驱动是没有任何问题的)
比如一段这样的代码
static DWORD kernelBase = 0;
DWORD GetKernelBase(VOID)
{
if ( kernelBase != 0 ) return kernelBase;
// 获取 kernelBase
// ...
}
本来这个函数首次执行时 kernelBase 应该是被初始化为0的, 但是跟踪调试中发现它的值并没有被初始化,
这就导致函数出错, 进而引发一系列奇怪的事情
这样就到了驱动中全局变量在何时初始化的问题上来了
本来我天真的以为全局变量应该是在程序编译时刻就被写到文件中了, 而通过反复对比我发现一些初始值非零的全局变量的值会被编译到文件中, 可初始值为零的全局变量就不会这样, 使用IDA观察的话这样的全局变量值会以问号形式标注其值
像这样
<这会发生在全局变量比较多, 代码量比较多的驱动中, 如果只有很少的全局变量, 它们也会被显示初始化为0>
那么既然不是在编译时刻赋值, 一定就是在运行时了, 但是驱动又不像应用层一样拥有一个运行时的初始化入口点, 所以最大的可能应该是在PE头中有什么被我所忽略的东西存在
通过反复观察终于在节区表中发现了端倪
我们知道全局变量一般都会被置于.data节区中, 仔细观察这个节区的属性会发现它在文件中的大小(SizeOfRawData)会比在内存中的大小(Misc)小得多, 下一个节区(.edata)在文件中的起始0x14200正好是.data节区在文件中起始+节区文件大小 0x14000+0x200, 但是在内存中该节区的布局是0x16000-0x18000, 那么除去文件中实际存在的数据大小 0x200 之外还有 0x18000-0x16000-0x200 大小的空间, 这部分空间存储的内容是什么呢?
没错, 它们都会初始化为空! 这样当有函数来引用它们时, 它们已经被初始化过了, 而那些初始值非零的全局变量统统会被编译到 0x200 那个空间中, 这样全部的全局变量都有了它们在代码阶段的初始值
回过头检查一下自己的代码, 自己拷贝节区的时候是按照节区在内存中的尺寸进行拷贝, 这样的话应该初始化为空.data节区区域就被跟随在.data节区后面的内容覆盖掉了, 所以导致了错误的发生
结论:实际上初始值为零的全局变量压根就没有编译到文件中, 编译器利用.data节区的内存空间布局给它们预留了足够的空间, 这样就间接对它们进行了初始化, 而且编译出来的文件大小也会更小
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)