XNA技术(C#) 打造黑客帝国屏保(上)
www.chengchen.net
在这篇文章中你可以学习到底层的逆向分析技术和微软最流行的顶层技术(什么都懂一点,生活更精彩)
1、 如何分析屏幕保护程序。
2、 如何使用C#的WPF技术编写屏幕保护程序。
3、 什么是XNA,怎样使用XNA编写简单动画。
早在高中时代,我就觉得屏幕保护技术是一件很神秘的事情。感觉这东西应该和底层关联的比较紧密,对于能写出屏保的程序员一直都很崇拜。梦想着哪天能写出自己的屏保,尤其是看过《黑客帝国》后那种酷酷的“数据流”界面,如果能做成屏保该有多好啊,现在这种感觉越来越强烈了。
终于按捺不住自己的情绪对屏保程序分析了一下,发现不是想象中的那么复杂,略有心得,特来和大家分享。
首先我们要解决的问题就是屏幕保护格式问题。只有知道了格式,我们才能按照这个格式打造。于是我尝试用UE打开system32目录下的logon.scr文件。惊人一幕出现了。
这不就是PE格式嘛。难道屏保是EXE文件或者DLL文件?于是尝试将logon.scr扩展名改为EXE运行,提示“此屏幕保护程序没有可提供设置的选项”。这里的提示和点击屏保标签页中的“设置”的提示是一致的。
从这点上可以说明,点击了“设置”按钮,貌似就是直接运行了屏保程序。也同时证明屏保程序就是EXE文件。但同时一个新的问题出现了:为何扩展名不同,运行结果不同呢?这其中究竟藏着什么秘密呢?于是我马上到MSDN网站上搜索,由于网速比较慢,搜了5分钟我就没耐心了,居然忘了我也具备一定的破解分析能力,于是直接拿OllyDBG出来研究……。
首先以logon.scr为研究对象吧,将它拷贝出来,修改扩展名为EXE,用OllyDBG载入程序,设断点 BP MessageBoxExW(NT时代的系统文件大部分是Unicode了)。运行程序,不一会儿程序就断了下来:

按下ALT+K,看看线程堆栈

看见logon.01001F54处就调用Message了,我们应该关注在Message之前程序干了什么,因此在堆栈的最先前执行的三个地址处下断。
分别是logon.010026F8 , logon.01002812, logon.0100294E
重新运行程序,程序立刻被断在了0100294E处,F7单步进入,发现一个JMP强跳,再单步发现如下代码:

看见那个GetCommandLineW的API了吗?这个API的作用是获得执行程序“命令行字符串”包括“参数”。当程序执行完毕这个API后,看看EXA得到了值:

(我把logon.exe放在D:\SetupFiles\目录下的。)
代码执行到这个地方:

此时又将“命令行信息”赋值到ESI中,程序先执行了一次CharNextW,将指针指向“命令行信息”第一个位置,判断第一个位置是否为0x22(双引号),然后再逐个字符来寻找“命令行信息”中的第二个双引号,一旦再次遇到双引号就跳出这个循环。继续执行代码又看到这样的循环:

这次是对比“命令行信息”中有无的0x20了,0x20代表空格,遇到空格就跳出循环。
看到这里我似乎明白了些什么了,总结一下:程序首先通过GetCommandLineW获得执行程序的“命令行信息”,然后在这个信息中找双引号。找到完双引号后再找空格。我敏感的神经告诉我,如果“命令行信息”中有空格,那么空格后面不就跟着参数嘛。如果程序有参数,执行了上面的操作,此时的指针就会指向ESI中的参数位置了。也就可以取到这个参数的值了。
我们不妨随便设置一个参数看看。打开OD的Debug菜单,点击“Arguments”。

随便设置一个启动参数,例如X吧。重新启动程序,正如我们分析的一样,程序在运行完一系列判断后,指针指向了参数位置。

那么程序是在什么地方判断参数的呢,不急,我们慢慢跟踪。在一个Call中发现如下代码:

此时的EAX值为0x78,不正是我们输入的参数“X”吗?下面是一堆的跳转,难道这里就是判断参数的地方?先看看,这个参数先和0x50对比,也就是“P”如果大于50就跳到这里来:

这里是和0x53对比 ,也就是和“S”对比。不管三七二十一,现将调试参数改为P试了一下,没什么反应,又将参数改为S试一试,发现成功执行屏幕保护。果然windows是根据参数信息来执行屏保程序的。只要慢慢跟踪就会挖出更多的参数,但是这样跟踪很显然是十分消耗体力的。我们用OD的目的只是为了调查屏保的实现原理,现在已经知道是用参数实现的,关于参数的获得除了使用OD,最简单的方法还是写个程序,读取参数并使用MessageBox弹出来。
[STAThread]
static void Main(string []arg)
{
if (arg.Length > 0)
{
MessageBox.Show(arg[0]);
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
随便写了一个测试程序,弹出参数信息并总结如下:
| |
|
|
|
| |
无参数时候 |
出现了属性对话框。 |
|
| |
参数为/C 的时候 |
在屏幕保护标签页上点击了设置按钮/ 鼠标右键选择设置菜单。 |
|
| |
参数为/S 的时候 |
运行屏幕保护程序/屏幕保护标签页上点击了预览按钮/鼠标右键选择测试菜单。 |
|
| |
参数为/P 的时候 |
在屏幕保护标签页上选择该屏保的时候。 |
|
| |
|
|
|
以上是在winxp上测试的,拿到虚拟机win98上测试,多了一个A的参数:在屏幕保护标签页上点击了密码保护更改按钮。
没想到分析一个屏保程序花了这么多篇幅,我还是在下一节介绍使用WPF技术创造自己的屏幕保护吧。
