6.1.1 思路——动态定位函数的地址

“ShellCode的执行过程就是调用函数的过程。”老师说道,“Windows下调用函数分为两步,一是参数入栈;二是CALL 函数地址。”

“那大家想想,我们前面写的ShellCode,各系统版本间不能混用,其原因是出在哪里呢?”

“原因……原因出于版本不同!”玉波回答道。

“晕!拿究竟是参数入栈不同,还是调用函数地址不同呢?”老师提醒大家。

“参数入栈部分看起来是一样的;拿应该时各个版本下函数的地址不同吧!”宇强分析道。

“对!系统不同,同一个函数的地址就不同。比如Windows 2000和XP,或者中文版XP和英文版XP,LoadLibrary函数的地址都不同;而且,同样的系统、同样的语言版本,SP补丁不同,函数的地址也不同。”

“哦,ShellCode的通用性就是要解决函数地址的通用性吧!”

“非常正确!”

“难道每个函数都存在各版本通用的隐藏地址?我们直接调用隐藏地址就行了?”玉波想起当年打C&C的隐藏关卡。

“这个我不知道,可能要问问比尔.盖茨才知道哦!”老师笑着说,“但系统可不像游戏。除了偶尔存在象tlEnterCriticalSection函数指针外,其他函数的地址都绝对不同!”

“那怎么完成通用的呢?真是‘Mission Impossible’啊!”大家苦苦思索。

“我提示一下,在ShellCode的编写中,我们曾用过GetProcAddress来获得其他函数的地址……”

“对啊!老师真是汤姆.克鲁斯啊!”大家顿觉山穷水尽疑无路,柳暗花明又一村,“我们不使用固定的函数地址,而是在ShellCode中先用GetProcAddress获得函数的地址——获得当时所在系统上的地址,然后在调用它!”

“呵呵?别人都说我是三重刘德华呢!”老师开玩笑的说,“很好!但除了GetProcAddress外,还需要知道LoadLibrary的地址;然后我们就可利用这两个函数来动态获得其他函数的地址,并存起来。以后,要调用函数时,就使用保存起来的地址,从而完成具有通用性的ShellCode!”

“哦,明白了!思路应该时这样。我们动态定位函数的地址再调用。”学生们画出了图6-1的示意图。

“对!就是这样!”老师看了看,满意的说。

“但如何获得GetProcAddress和LoadLibrary的地址呢?”老师又问道。

大家又愣住了,“是啊,怎么获得呢?好像这两个函数的地址并没有宇宙通用版啊!”

“大家能想到这里,很不错!这也是早期ShellCode卡住的地方。”老师说道,“当人们对宇宙、对地球、对Windows系统不断的深入认识后,终于有了解决的方法。”

“哦?这么厉害,什么方法?”

“就是利用Windows的系统结构来获得GetProcAddress和LoadLibrary函数的地址。”