远线程技术之一--DLL注入

WinNT/Win2000/WinXP中的远线程技术之一--DLL注入
        什么是远线程?我们知道用CreateThread可以在当前进程里建立一个线程,远线程与此类似,只不过是在其他进程中建立一个线程,用API函数CreateRemoteThread。这个远线程建立后就与建立它的进程无关了,而是进入了另外一个进程。举例说,进程A可以在进程B中建立一个远线程,这个远线程就是进程B中的线程了,而此时如果进程A结束了,也不会影响到那个远线程的运行,除非进程B也结束了,那个远线程才会结束。怎么样,是不是很神奇啊?现在我们来看看怎么建立远线程。
        最简单的远线程技术是DLL注入。好,先从这个讲起。所谓DLL注入就是将一个DLL放进某个进程的地址空间里,让它成为那个进程的一部分。要实现DLL注入,首先需要打开目标进程。
hRemoteProcess   =   OpenProcess( PROCESS_CREATE_THREAD   |   //允许远程创建线程  
      PROCESS_VM_OPERATION |   //允许远程VM操作
      PROCESS_VM_WRITE, //允许远程VM写
      FALSE,   dwRemoteProcessId   )
由于我们后面需要写入远程进程的内存地址空间并建立远程线程,所以需要申请足够的权限(PROCESS_CREATE_THREAD、VM_OPERATION、VM_WRITE)。
如果进程打不开,以后的操作就别想了。进程打开后,就可以建立远线程了,不过别急,先想想这个远线程的线程函数是什么?我们的目的是注入一个DLL。而且我们知道用LoadLibrary可以加载一个DLL到本进程的地址空间。于是,自然会想到如果可以在目标进程中调用LoadLibrary,不就可以把DLL加载到目标进程的地址空间了吗?对!就是这样。远线程就在这儿用了一次,建立的远线程的线程函数就是LoadLibrary,而参数就是要注入的DLL的文件名。(这里需要自己想一想,注意到了吗,线程函数ThreadProc和LoadLibrary函数非常相似,返回值,参数个数都一样)   还有一个问题,LoadLibrary这个函数的地址在哪儿?也许你会说,这个简单,GetProcAddress就可以得出。于是代码就出来了。
char   *pszLibFileRemote= "my.dll ";
PTHREAD_START_ROUTINE   pfnStartAddr   =   (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle( "Kernel32 "),   "LoadLibraryA ");
CreateRemoteThread(   hRemoteProcess,   NULL,   0,   pfnStartAddr,   pszLibFileRemote,   0,   NULL);
        但是不对!不要忘了,这是远线程,不是在你的进程里,而pszLibFileRemote指向的是你的进程里的数据,到了目标进程,这个指针都不知道指向哪儿去了,同样pfnStartAddr这个地址上的代码到了目标进程里也不知道是什么了,不知道是不是你想要的LoadLibraryA了。但是,问题总是可以解决的,Windows有些很强大的API函数,他们可以在目标进程里分配内存,可以将你的进程中的数据拷贝到目标进程中。因此pszLibFileRemote的问题可以解决了。
char   *pszLibFileName= "my.dll ";//注意,这个一定要是全路径文件名,除非它在系统目录里;原因大家自己想想。
//计算DLL路径名需要的内存空间
int   cb   =   (1   +   lstrlenA(pszLibFileName))   *   sizeof(char);
//使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区
pszLibFileRemote   =   (char   *)   VirtualAllocEx(   hRemoteProcess,   NULL,   cb,   MEM_COMMIT,   PAGE_READWRITE);
//使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间
iReturnCode   =   WriteProcessMemory(hRemoteProcess,   pszLibFileRemote,   (PVOID)   pszLibFileName,   cb,   NULL);
        OK,现在目标进程也认识pszLibFileRemote了,但是pfnStartAddr好像不好办,我怎么可能知道LoadLibraryA在目标进程中的地址呢?其实Windows为我们解决了这个问题,LoadLibraryA这个函数是在Kernel32.dll这个核心DLL里的,而这个DLL很特殊,不管对于哪个进程,Windows总是把它加载到相同的地址上去。因此你的进程中LoadLibraryA的地址和目标进程中LoadLibraryA的地址是相同的(其实,这个DLL里的所有函数都是如此)。至此,DLL注入结束了。
参考文献:《Windows核心编程技术》
WinNT/Win2000/WinXP中的远线程技术之二--甩掉那个DLL
        在《远线程技术之一》里我们已经能够将一个DLL注入到其他进程里了,但用某些工具(例如本站的DllShow)可以看到被注入的DLL的详细情况,比如DLL所在目录等。本文将讲述另一种建立远线程的方法,直接在其他进程里注入代码,而不需要什么DLL。
        回忆一下DLL注入的方法,需要向目标进程写入一些数据(如DLL的全路径文件名),既然能写入数据,那么就可以写入执行代码。这样就可以不借助于DLL在其他进程里建立一个远线程了。
        基本思路就是这样,写一个线程函数,然后把整个线程函数写入目标进程,然后启动它。当然,怎么确定线程函数在内存中的大小是个难题,我的方法就是用函数指针的差值再加上1024字节,这个方法肯定不好,但我也没想到什么好办法,谁有好办法可以给我留言。
        这是我写的例子,远线程启动后每一秒响铃一次(BEEP)
参考文献:本站的《远线程技术之一》,农民网站:   http://nongmin-cn.8u8.com/index.htm  
WinNT/Win2000/WinXP中的远线程技术之三--DLL回来了
        在《远线程技术之二》里,我们已经可以不借助DLL来直接向其他进程注入代码了,但是这个方法实在是太麻烦了,因为几乎所有的函数都要动态调用,写代码很费时间。因此想到了先将DLL注入到目标进程并得到一个启动函数的地址(启动函数就是你自己写在DLL中的一个函数,调用它可以完成你需要的功能),然后将DLL所占的内存做一个拷贝,卸载DLL,再把拷贝还原到原来DLL所占的那一块内存,这样就好像DLL仍然存在一样,然后就可以通过刚才的启动函数的地址启动你的函数了。这种方法的好处是DLL中的函数调用都是操作系统管理,不需要自己动态调用,编写容易。
        这种方法需要得到的信息主要有三个,1)DLL的起始地址,这其实就是LoadLibrary的返回值,2)启动函数的地址,这可以通过GetProcAddress得到,3)DLL所占内存大小,我调用了一个API函数GetModuleInformation,根据MSDN的说明好像可以,这个函数只有WinNT4以上版本才能使用,不过反正CreateRemoteThread也只能用于WinNT,所以就无所谓了。而我参考的农民的代码是读取文件得到这个值的。
        其他就没有什么特别难的地方了,如果能构看懂《远线程技术之二》的代码,那么这个也不会有什么问题了。
        我写了个例子,可以把你自己写的DLL注入到某个进程,并执行你在DLL中输出的函数Start(),以下是DLL例子的代码。
//---------------------------------------------------------------------------
//这是一个时间服务器的例子

#include   <windows.h>
#include   <winsock.h>
#include   <stdio.h>

char   *weekday[7]={ "Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat "};
char   *month[12]={ "Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "};

DWORD   WINAPI   MyThreadProc(LPVOID   lpParameter)
{
int   sock;
struct   sockaddr_in   server;
int   msgsock;
char   systime[1024];
int   rval;
WSADATA   WsaData;
SYSTEMTIME   t;

if(WSAStartup(MAKEWORD(2,0),&WsaData)==-1)
return   1;
sock=socket(AF_INET,SOCK_STREAM,0);
if(sock <0)
return   2;
server.sin_family   =AF_INET;
server.sin_port   =htons(13);
server.sin_addr.s_addr   =INADDR_ANY;
if(bind(sock,(const   struct   sockaddr   *)&server,sizeof(server)) <0)
return   3;
listen(sock,SOMAXCONN);
while(1)
{
msgsock=accept(sock,NULL,NULL);
GetSystemTime(&t);
sprintf(systime,
"%s   %s   %02d   %02d:%02d:%02d   %04d\n ",
weekday[t.wDayOfWeek],
month[t.wMonth-1],
t.wDay   ,
t.wHour   ,
t.wMinute   ,
t.wSecond   ,
t.wYear   );
send(msgsock,systime,lstrlen(systime),MSG_OOB);
closesocket(msgsock);
}
return   0;
}

extern   "C "   __declspec(dllexport)   __stdcall   void   Start()//这个是需要导出的启动函数
{
DWORD   TID;
CreateThread(NULL,0,MyThreadProc,NULL,0,&TID);
}

int   WINAPI   DllEntryPoint(HINSTANCE   hinst,   unsigned   long   reason,   void*   lpReserved)
{
return   1;
}
//---------------------------------------------------------------------------
参考文献:本站的《远线程技术之二》,农民网站:   http://nongmin-cn.8u8.com/index.htm
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值