【文章标题】:为任意程序添加SplashScreen
【文章作者】: Kangaroo
【软件名称】: 任意
【下载地址】: 附件
【使用工具】: VC、LoarPE
【操作平台】: Winsp2
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教,该文章本人已在黑客防线2006年第8期发表。
相信玩过逆向工程的人,都会给任意的exe文件加入MessageBox吧(也就是在程序启动前先弹出个MessageBox对话框,当用户点击确定的时候,进入程序),我先总结下上述过程的实现方法,然后进入本文的主题:
一、在.data段找到cave地方,输入MessageBox显示的字符串
二、在.text段找到cave地方(主要用来写patch代码)
.004012B4: 6A00 push 000 (类型)
.004012B6: 682C314000 push 00040312C(标题字符串地址)
.004012BB: 6848314000 push 000403148(内容字符串地址)
.004012C0: 6A00 push 000(句柄)
.004012C2: FF1518204000 call MessageBoxA(调用函数)
.004012C8: E933FDFFFF jmp .000401000(跳到原oep处)
三、用LordPE将程序的OEP修改为004012B4
至此就成功的插入了个MessageBox
好了,费话说了那么多,现在我们的主要目标不是为exe文件插入MessageBox,而是为exe文件插入splashscreen(程序启动界面,例如Photoshop、Flash等大型软件都有漂亮的启动界面),相信大家目前已经想到用上面的方法同样实现吧,别急,想想可行性:
一、需要调用CreateWindow来创建窗口,并为该窗口指定一个消息处理函数,然后在WM_CREATE处调用SetTimer创建时间器,接着在WM_PAINT分支加载图片,在WM_TIMER分支处关闭窗口,当窗口关闭时需要回到原程序入口点,继续执行,使原程序能够正常工作(SDK编程基础)
二、如果上述需要用的函数在输入表中没有的话,那就需要我们自己去导入这些函数了
上述问题就意味着你需要patch大量的代码,这样即使你有足够的精力去做的话,那也必将浪费掉大量的时间如何快速插入一个splashscreen这将是我们最大的挑战。
分析:
分析下PE装载器的工作原理,相信会有事半功倍的效果,PE装载首先找到输入表中程序需要用到的函数,然后并将该函数所在的DLL加载到进程空间中(在加载DLL到进程空间时,PE装载器将会调用DLL中的DllMain函数,执行完该函数后,继续加载其它动态库,最后进入程序入口点执行程序....)
哈哈,这不是我们正想要的地方吗?如果我们在DllMain中调用DialogBoxParam函数,在资源中创建对话框(DialogBoxParam函数直到对话关闭时才返回,这意为着当我们的对话没有关闭前,DllMain函数不可能执行完毕,根据上面PE装载器工作过程的分析在对话框关闭前程序不可能执行,此时PE装载器在等DllMain函数退出嘛,然后在继续加载其它模块,最后主程序才开始执行。)这样不正好产生了SplashScreen效果!!!
实现:
创建个dll工程,加入如下代码:
#include "stdafx.h"
int DummyFunc() //空函数
{
return 0;//这个空函数一定需要,我们把它放入到dll的输出表中
//因为等下我们需要把该函数加入到我们需要加添加splashscreen的程序的输入表中,如果该dll一个输出函数都没有,那我们将无法为原程序添加输入函数,也间接意味着,PE装载器不会加载我们写的dll到程序的进程空间中去。
}
BOOL DlgProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
DWORD TimerID;
switch(msg)
{
case WM_CLOSE:
{
KillTimer(hwnd, TimerID);
EndDialog(hwnd, 0);
}
break;
case WM_INITDIALOG:
{
int ScreenWidth,ScreenHeight,StartPosX,StartPosY,WndWidth,WndHeight;
RECT WndRect;
ScreenWidth=::GetSystemMetrics(SM_CXSCREEN);
ScreenHeight=::GetSystemMetrics(SM_CYSCREEN);
::GetWindowRect(hwnd,&WndRect);
WndWidth=WndRect.right-WndRect.left;
WndHeight=WndRect.bottom-WndRect.top;
TimerID = SetTimer(hwnd, 466, 3000, NULL);
//呵呵,这里插入点汇编,主要是跟大家介绍下,右移是除以二,左移是乘以二(移位指令比除法指令快的,希望大家能接受这一思想),这顺便介绍了如何在C++中插入汇编。下面这段算法主要是将窗口显示在屏幕的中央。
__asm{
mov eax,ScreenWidth
sub eax,WndWidth
shr eax,1 //右移1位等价于除以2
mov StartPosX,eax
mov eax,ScreenHeight
sub eax,WndHeight
shr eax,1
mov StartPosY,eax
}
//上面代码的等价C++代码如下:
// StartPosX=(ScreenWidth-WndWidth)>>1;
// StartPosY=(ScreenHeight-WndHeight)>>1;
SetWindowPos(hwnd,HWND_TOPMOST,StartPosX,StartPosY,WndWidth,WndHeight,SWP_HIDEWINDOW);
}
break;
case WM_TIMER:
{
SendMessage(hwnd, WM_CLOSE,0,0);
}
break;
default:break; }
return FALSE;
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD fdwReason,LPVOID lpReserved)
{ switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
{
DialogBoxParam((HINSTANCE)hModule, MAKEINTRESOURCE(102), NULL, (DLGPROC)DlgProc, NULL);
}
break;
case DLL_PROCESS_DETACH:
{
}
break;
}
return TRUE;
}
一定需要把建立个def文件,将dummyfunc函数导出
Def文件内容如下:
LIBRARY
EXPORTS
DummyFunc
OK! 上面已经给出了主要代码了,至于资源方面的设计相信大家都会,这里就不在多说。(具体见源代码)接下来,我们需要讲的是,如何使用我们这个dll,刚才不是说了吗?需要将我们刚才输出的DummyFunc添加到我们需要修改的程序的输入表中,手动添加当然可以(这要求对PE文件的结构有足够的了解),不过现在教大家用工具快速添加,打开LordPE,加载我们需要修改的exe文件,如图一:
选择Directories按钮,弹出对话框,如图二:
选择ImportTable右边的…按钮,此时再次弹出个对话,我们就可以为该程序加入函数了。如图三:
点击add import,在弹出的对话框中,如下设置(如图四)
选择+按钮,此时成功加入,OK至此,我们已经成功的为一个程序加入了SplashScreen了如果想为其它程序加入,此时只要带上我们写的动态库,和LordPE就可以快速搞定,哈哈,爽吧!
总结:
程序中给出了两种方案,第一种方案只适用于写patch代码量比较小的程序,而第二种方案你就能彻底的为程序添加丰富的功能了,包括木马的后门等,这就需要大家多动动脑,在此我就不多说了。