代码注入之远程线程篇

14 篇文章 0 订阅
订阅专栏

引子

    

转自: 小宝马的爸爸 - 博客园

     

前些日子由于项目要求,在网上到处找资料,于无意中发现了 CodeProject 上的一篇很老的文章,文章标题为:

Three Ways to Inject Your Code into Another Process

这篇文章呢,出来很久咯,还是 03 年的文章了,可惜我弄底层弄得时间不久哦,不然应该早就看过这篇大作了,

由于是大作,而且出来的又久了,自然在网上也就到处流传咯,

所以也有人将这篇文章翻译成了中文版的,下面给出这篇大作的两个链接:

中文版: http://www.vckbase.com/document/viewdoc/?id=1886

英文版: http://www.codeproject.com/KB/threads/winspy.aspx

然后呢,这边由于老大给弄了蛮多好书过来了,其中一本就是所谓的骇客之类的东西,

虽然是繁体的,但是知识点都很不错哦,所以也拿过来看了看,就发现其中对这个远程线程的注入有很多的介绍,

而且貌似前些年的很多病毒或者木马就是通过这屁东西来隐藏的,

看着看着就来劲了,而后呢,自己就根据书中的思路,

然后再结合自己的理解,将理解整理出了代码,然后就出了这篇文章咯 !

然后注意一点的是,在 CodeProject 上的那篇文章中介绍了三种注入代码技术,

第一种就是众所周知的 Hook 了;

第二种是直接将所要执行的代码全部拷贝到宿主进程中,即代码远程注入技术;

第三种则是 DLL 的远程注入技术了,其通过在宿主进程加载自己写的另外的一个 DLL 来实现注入;

然后在我的这篇博文中,我也只是总结前人的思想,然后再加入我自己的立即,

同时由于 Hook 太常见了,常见得不行了,所以我并不会介绍 Hook 了,而只介绍后面的两种方式。

          

            

代码远程注入技术

    

Demo 的效果:

创建的项目为 RemoteThreadCode,即远程注入代码,其实现的功能是当运行 RemoteThreadCode.exe 时,

会在 Explorer.exe 进程中创建一个线程,而这个创建的线程功能实现很简单,

就是弹出一个消息框即 OK !

      

Demo 的效果展示:

当双击执行 RemoteThreadCode.exe 时,则会注入一个线程到 Explorer.exe 中

image

             

当点击确定后,注入到 Explorer.exe 中的线程执行完毕,从而 WaitForSingleObject 等待成功 !

image

          

基本思路以及所对应的代码:

1. 提升进程权限,如果权限不够的话,很容易造成 OpenProcess 失败;

   1: //=====================================================================================//
   2: //Name: bool AdjustProcessTokenPrivilege()                                             //
   3: //                                                                                     //
   4: //Descripion: 提升当前进程权限                                                                 //
   5: //=====================================================================================//
  
bool AdjustProcessTokenPrivilege()
{
     LUID luidTmp;
     HANDLE hToken;
     TOKEN_PRIVILEGES tkp;
  
     if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
     {
         OutputDebugString("AdjustProcessTokenPrivilege OpenProcessToken Failed ! \n");
 
        return false;
     }
  
     if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidTmp))
     {
         OutputDebugString("AdjustProcessTokenPrivilege LookupPrivilegeValue Failed ! \n");
  
         CloseHandle(hToken);
  
         return FALSE;
     }
  
     tkp.PrivilegeCount = 1;
     tkp.Privileges[0].Luid = luidTmp;
     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  
     if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
     {
         OutputDebugString("AdjustProcessTokenPrivilege AdjustTokenPrivileges Failed ! \n");
  
         CloseHandle(hToken);
    
           return FALSE;
       }
      return true;
}

 
 
2. 确定你的宿主进程,即你所要注入代码的进程,这个其实很好办,你要是不想你的木马或者病毒被别个一下子就结束了的话,

   最好是选择系统要想运行,则必须开启的那种进程,比如资源管理器进程 Explorer.exe,

   Windows 子系统进程 csrss.exe 等等,但是这里注意的是,我注入 System 进程的时候造成了失败哦,

   所以最好还是别拿 System 做实验,而且如果你注入失败了的话,是会造成宿主进程崩溃的,

   等下一不小心把 System 进程给弄崩溃了就不好了;

   1: //=====================================================================================//
   2: //Name: bool ProcessIsExplorer(DWORD dwProcessId)                                      //
   3: //                                                                                     //
   4: //Descripion: 判定一个进程是否为 Explorer 进程                                                 //
   5: //=====================================================================================//
   6: bool ProcessIsExplorer(DWORD dwProcessId)
   7: {
   8:     HANDLE hProcess;
   9:  
  10:     hProcess = NULL;
  11:  
  12:     hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
  13:     if(NULL == hProcess)
  14:     {
  15:         OutputErrorMessage("ProcessIsExplorer - OpenProcess Failed , Error Code Is %d , Error Message Is %s !");
  16:  
  17:         return FALSE;
  18:     }
  19:  
  20:     DWORD dwNameLen;
  21:     TCHAR pathArray[MAX_PATH];
  22:     ZeroMemory(pathArray, MAX_PATH);
  23:  
  24:     dwNameLen = 0;
  25:     dwNameLen = GetModuleFileNameEx(hProcess, NULL, pathArray, MAX_PATH);
  26:     if(dwNameLen == 0)
  27:     {
  29:         CloseHandle(hProcess);
  30:  
  31:         return FALSE;
  32:     }
  33:  
  34:     TCHAR exeNameArray[MAX_PATH];
  35:     ZeroMemory(exeNameArray, MAX_PATH);
  36:     _tsplitpath(pathArray, NULL, NULL, exeNameArray, NULL);
  37:  
  38:     string str1 = exeNameArray;
  39:     if((str1.compare("Explorer") == 0) || (str1.compare("explorer") == 0))
  40:     {
  41:         CloseHandle(hProcess);
  42:  
  43:         return TRUE;
  44:     }
  45:  
  46:     return FALSE;
  47: }

3. 打开宿主进程了(我这里打开的是 Explorer.exe 进程),思路是首先变量当前系统下运行的所有的进程,

   然后遍历获取到得所有的进程的 PID,再调用 ProcessIsExplorer 函数来判断这个进程是否为 Explorer.exe 进程,

   如果是则记录下这个进程的 PID 就可以了,这样就获得了 Explorer.exe 进程的 PID 了,

   再通过 OpenProcess 来打开这个 Explorer.exe 进程就 OK 了;

 //提升当前进程的权限
 AdjustProcessTokenPrivilege();
  
 //第一个参数为用来保存所有的进程 ID
 //第二个参数则是第一个参数的字节数
 //第三个参数则是写入 dwProcess 数组的字节数

DWORD dwProcess[1024],dwNeeded,cprocesses;
HANDLE hprocess;
//HMODULE hmodule;
//UINT i;
EnumProcesses(dwProcess, sizeof(dwProcess), &dwNeeded);

//找到 explorer.exe 进程的 ID
dwExplorerId = 0;
for(int i = 0; i < dwNeeded / sizeof(DWORD); i++)
{
	if(0 != dwProcess[i])
	{
		if(ProcessIsExplorer(dwProcess[i]))
		{
			dwExplorerId = dwProcess[i];
			break;
		}
	}
}

hProcess = NULL;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwExplorerId);
if(NULL == hProcess)
{
	OutputErrorMessage("main - OpenProcess Failed , Error Code Is %d , Error Message Is %s !");
}
printf("successful!");

 
 

4. 在宿主进程中分配好存储空间,这个存储空间是用来存放我们将要创建的远程线程的线程处理例程的,

   这里需要注意的是:我们分配的内存必须标记必须带有 EXECUTE,因为分配的这块内存是用来存放线程处理例程的,

   而线程处理例程必须得执行,所以必须得带有 EXECUTE 标记,而至于 WRITE 标记的话,很明显是需要的,

   因为我们在后面的代码中还必须调用 WriteProcessMemory 来将线程处理例程写入到这块内存中,自然其必须可写;

   1: //在 hProcess 所代表的进程内部分配虚拟内存来容纳我们将要创建的远程线程
   2: PVOID pRemoteThread = VirtualAllocEx(hProcess, NULL, THREAD_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
   3: if(NULL == pRemoteThread)
   4: {
   5:     OutputErrorMessage("main - VirtualAllocEx Failed , Error Code Is %d , Error Message Is %s !");
   6:  
   7:     //关闭进程句柄
   8:     CloseHandle(hProcess);
   9: }

5. 将远程线程处理例程写入到 4 中在宿主进程中所分配的内存中,这个可以直接调用 WriteProcessMemory 来实现;

   1: //往我们在 hProcess 进程中分配的虚拟内存里面写入数据,这里主要是将整个线程都写进去
   2: if(WriteProcessMemory(hProcess, pRemoteThread, &RemoteThreadProc, THREAD_SIZE, 0) == FALSE)
   3: {
   4:     OutputErrorMessage("main - WriteProcessMemory Failed , Error Code Is %d , Error Message Is %s !");
   5:  
   6:     //释放 VirtualAllocEx 分配的内存
   7:     VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
   8:     CloseHandle(hProcess);
   9: }

6. 在宿主进程中分配好存储空间,这个存储空间是用来存放我们将要传递给远程线程线程处理例程的参数,

   从下面的结构体中可以看出,其由三个参数组成,第一个参数代表要在对话框中显示的内容,

   第二个参数代表要在对话框中显示的标题,第三个参数则是 MessageBox 这个 API 的地址,

   因为在 Explorer.exe 中 MessageBox 的地址会发生重定向,所以需要将其地址通过参数传递给线程处理例程;

   1: typedef struct _REMOTE_PARAMETER
   2: {
   3:     CHAR m_msgContent[MAX_PATH];
   4:     CHAR m_msgTitle[MAX_PATH];
   5:     DWORD m_dwMessageBoxAddr;
   6:  
   7: }RemotePara, * PRemotePara;
          
   1: //=====================================================================================//
   2: //Name: void GetMessageBoxParameter(PRemotePara pRemotePara)                           //
   3: //                                                                                     //
   4: //Descripion: 获得 MessageBox 这个 API 的地址以及填充的参数                                     //
   5: //=====================================================================================//
   6: void GetMessageBoxParameter(PRemotePara pRemotePara)
   7: {
   8:     HMODULE hUser32 = LoadLibrary("User32.dll");
   9:     
  10:     pRemotePara->m_dwMessageBoxAddr = (DWORD)GetProcAddress(hUser32, "MessageBoxA");
  11:     strcat(pRemotePara->m_msgContent, "Hello, Zachary.XiaoZhen !\0");
  12:     strcat(pRemotePara->m_msgTitle, "Hello\0");
  13:     
  14:     //注意要释放掉 User32
  15:     FreeLibrary(hUser32);
  16: }

           

   1: RemotePara remotePara;
   2: ZeroMemory(&remotePara, sizeof(RemotePara));
   3: GetMessageBoxParameter(&remotePara);
   4:  
   5: //在 hProcess 所代表的进程中分配虚拟内存来容纳线程的参数部分
   6: PRemotePara pRemotePara = (PRemotePara)VirtualAllocEx(hProcess, NULL, sizeof(RemotePara), MEM_COMMIT, PAGE_READWRITE);
   7: if(NULL == pRemotePara)
   8: {
   9:     OutputErrorMessage("main - VirtualAllocEx Failed , Error Code Is %d , Error Message Is %s !");
  10:  
  11:     //释放 VirtualAllocEx 分配的内存
  12:     VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
  13:     CloseHandle(hProcess);
  14: }

7. 将参数写入到 6 中在宿主进程中所分配的内存中,同样是调用 WriteProcessMemory 来完成;

   1: //往在 hProcess 进程中分配的虚拟内存中写入参数数据
   2: if(WriteProcessMemory(hProcess, pRemotePara, &remotePara, sizeof(RemotePara), 0) == FALSE)
   3: {
   4:     OutputErrorMessage("main - WriteProcessMemory Failed , Error Code Is %d , Error Message Is %s !");
   5:     //释放 VirtualAllocEx 分配的内存
   6:     VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
   7:     VirtualFreeEx(hProcess, pRemotePara, 0, MEM_RELEASE);
   8:  
   9:     CloseHandle(hProcess);
  10: }

8. 调用 CreateRemoteThread 在 Explorer.exe(宿主进程)中创建远程线程;

   注意,当远程线程没有执行完时,不能够通过 VirtualFreeEx 来将远程进程中的内存释放掉,

   你想啊,我他妈的线程都还在 Explorer.exe 里面执行,你他妈的在外面把我占的内存给释放掉了,我还执行个屁啊 !

   所以这里调用了 WaitForSingleObject 来等待这个远程线程执行完毕,

   其执行完毕后再释放在 Explorer.exe 中所分配的存储空间 !

   1: HANDLE hThread;
   2: DWORD dwThreadId;
   3:  
   4: hThread = NULL;
   5: dwThreadId = 0;
   6:  
   7: //将已经写入到 hProcess 进程中的线程以及线程的参数作为 CreateRemoteThread 的参数,从而创建远程线程
   8: hThread = CreateRemoteThread(hProcess, NULL, 0, (DWORD (WINAPI *)(LPVOID))pRemoteThread, pRemotePara, 0, &dwThreadId);
   9: if(NULL == hThread)
  10: {
  11:     OutputErrorMessage("main - CreateRemoteThread Failed , Error Code Is %d , Error Message Is %s !");
  12: }
  13: else
  14: {
  15:     OutputSuccessMessage("Code Inject Success !");
  16: }
  17:  
  18: //等待远程线程结束
  19: WaitForSingleObject(hThread, INFINITE);
  20: CloseHandle(hThread);
  21:  
  22: //必须等到远程线程结束后才能释放宿主进程中所分配的内存,否则宿主进程会直接崩溃
  23: //释放 VirtualAllocEx 分配的内存
  24: VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
  25: VirtualFreeEx(hProcess, pRemotePara, 0, MEM_RELEASE);
  26:  
  27: CloseHandle(hProcess);

9. 编写好远程线程的线程处理例程即可;

   1: //=====================================================================================//
   2: //Name: bool RemoteThreadProc(LPVOID lpParameter)                                      //
   3: //                                                                                     //
   4: //Descripion: 远程线程处理例程                                                                 //
   5: //=====================================================================================//
   6: DWORD WINAPI RemoteThreadProc(PRemotePara pRemotePara)
   7: {
   8:     //这个 MessageBox 的地址必须由外部参数传入,因为在其他进程中需要重定向
   9:     typedef int (WINAPI *MESSAGEBOXA)(HWND, LPCSTR, LPCSTR, UINT);
  10:  
  11:     MESSAGEBOXA MessageBoxA;
  12:     MessageBoxA = (MESSAGEBOXA)pRemotePara->m_dwMessageBoxAddr;
  13:  
  14:     //调用 MessageBoxA 来打印消息
  15:     MessageBoxA(NULL, pRemotePara->m_msgContent, pRemotePara->m_msgTitle, MB_OK);
  16:  
  17:     return 0;
  18: }

          

           

DLL 远程注入技术

      

Demo 的效果:

创建的项目为 RemoteThreadDll,即远程注入 DLL,其实现的功能是当运行 RemoteThreadDll.exe 时,

会在 Explorer.exe 进程中创建一个线程,而这个创建的线程功能实现则相对于上面的远程注入代码来说复杂一点,

在线程的处理例程中,首先是由线程参数传递过来的 LoadLibrary 的地址

和 GetProcAddress 的地址来找到 LoadLibrary 和 GetProcAddress API,

然后再通过 LoadLibrary(“MyDllName”) 来加载到我自己的 DLL,

然后再通过 GetProcAddress 在这个 DLL 中找到我的 DLL 所公开的函数,

再就是调用这个公开的函数了,我新建的 DLL 项目为 – ZacharyDll.dll,

该 DLL 中导出了两个函数,一个函数用来弹出一个对话框,一个函数则是用来打印出调试信息;

           

Demo 的效果展示:

当双击执行 RemoteThreadCode.exe 时,则会注入一个线程到 Explorer.exe 中,

而后注入的这个线程就会调用我自己的 ZacharyDll.dll,

再调用 ZacharyDll.dll 中导出的两个函数了,一个输出调试信息,一个弹出对话框:

image

当点击确定后,注入到 Explorer.exe 中的线程执行完毕,从而 WaitForSingleObject 等待成功 !

image

         

基本思路以及所对应的代码:

1. 提升进程权限,如果权限不够的话,很容易造成 OpenProcess 失败;

   这一部分的代码同上面的远程注入代码是一样的;

    

2. 确定你的宿主进程,即你所要注入代码的进程,这个其实很好办,你要是不想你的木马或者病毒被别个一下子就结束了的话,

   最好是选择系统要想运行,则必须开启的那种进程,比如资源管理器进程 Explorer.exe,

   Windows 子系统进程 csrss.exe 等等,但是这里注意的是,我注入 System 进程的时候造成了失败哦,

   所以最好还是别拿 System 做实验,而且如果你注入失败了的话,是会造成宿主进程崩溃的,

   等下一不小心把 System 进程给弄崩溃了就不好了;

   这一部分的代码同上面的远程注入代码是一样的;

            

3. 打开宿主进程了(我这里打开的是 Explorer.exe 进程),思路是首先变量当前系统下运行的所有的进程,

   然后遍历获取到得所有的进程的 PID,再调用 ProcessIsExplorer 函数来判断这个进程是否为 Explorer.exe 进程,

   如果是则记录下这个进程的 PID 就可以了,这样就获得了 Explorer.exe 进程的 PID 了,

   再通过 OpenProcess 来打开这个 Explorer.exe 进程就 OK 了;

   这一部分的代码同上面的远程注入代码是一样的;

           

4. 在宿主进程中分配好存储空间,这个存储空间是用来存放我们将要创建的远程线程的线程处理例程的,

   这里需要注意的是:我们分配的内存必须标记必须带有 EXECUTE,因为分配的这块内存是用来存放线程处理例程的,

   而线程处理例程必须得执行,所以必须得带有 EXECUTE 标记,而至于 WRITE 标记的话,很明显是需要的,

   因为我们在后面的代码中还必须调用 WriteProcessMemory 来将线程处理例程写入到这块内存中,自然其必须可写;

   这一部分的代码同上面的远程注入代码是一样的;

         

5. 将远程线程处理例程写入到 4 中在宿主进程中所分配的内存中,这个可以直接调用 WriteProcessMemory 来实现;

   这一部分的代码同上面的远程注入代码是一样的;

        

6. 在宿主进程中分配好存储空间,这个存储空间是用来存放我们将要传递给远程线程线程处理例程的参数,

   从下面的结构体中可以看出,其由六个参数组成,

   第一个参数代表 ZacharyDll.dll 中导出的 PrintMessageBox 的名称,

   第二个参数代表 ZacharyDll.dll 中导出的 PrintDbgStr 的名称题,

   第三个参数则是 ZacharyDll.dll 所在的路径,

   第四个参数则是代表 LoadLibrary 的地址,

   第五个参数代表 FreeLibrary 的地址,

   第六个参数代表 GetProcAddress 的地址;

   1: #define DLLNAME "\\ZacharyDll.dll\0"
   2:  
   3: typedef struct _REMOTE_PARAMETER
   4: {
   5:     CHAR m_printMsgBox[MAX_PATH];
   6:     CHAR m_printDbgStr[MAX_PATH];
   7:     CHAR m_strDllPath[MAX_PATH];
   8:     DWORD m_dwLoadLibraryAddr;
   9:     DWORD m_dwFreeLibraryAddr;
  10:     DWORD m_dwGetProcAddrAddr;
  11:  
  12: }RemotePara, * PRemotePara;

          

   1: HMODULE hKernel32 = GetModuleHandle("Kernel32");
   2: if(NULL == hKernel32)
   3: {
   4:     OutputErrorMessage("main - GetModuleHandle Failed , Error Code Is %d , Error Message Is %s !");
   5:  
   6:     //释放 VirtualAllocEx 分配的内存
   7:     VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
   8:     CloseHandle(hProcess);
   9: }
  10: else
  11: {
  12:     RemotePara remotePara;
  13:     ZeroMemory(&remotePara, sizeof(RemotePara));
  14:  
  15:     //将 LoadLibraryA、FreeLibrary 和 GetProcAddress 三个 Kernel32 API 的地址保存到 remotePara 中
  16:     remotePara.m_dwLoadLibraryAddr = (DWORD)GetProcAddress(hKernel32, "LoadLibraryA");
  17:     remotePara.m_dwFreeLibraryAddr = (DWORD)GetProcAddress(hKernel32, "FreeLibrary");
  18:     remotePara.m_dwGetProcAddrAddr = (DWORD)GetProcAddress(hKernel32, "GetProcAddress");
  19:  
  20:     string strMsgBox = "PrintMessageBox";
  21:     string strBbgStr = "PrintDebugString";
  22:  
  23:     CHAR tmpArray[MAX_PATH];
  24:     CHAR * pTmpMsgBoxArray = "PrintMessageBox";
  25:     CHAR * pTmpDbgStrArray = "PrintDebugString";
  26:     
  27:     //将 ZacharyDll.dll 中导出的 API 的名称保存到 remotePara 中
  28:     strcpy(remotePara.m_printMsgBox, pTmpMsgBoxArray);
  29:     strcpy(remotePara.m_printDbgStr, pTmpDbgStrArray);
  30:  
  31:     ZeroMemory(tmpArray, MAX_PATH);
  32:  
  33:     //获取到当前路径
  34:     GetCurrentDirectory(MAX_PATH, tmpArray);
  35:     
  36:     //路径加上 DLL 名称(从而可以将 DLL 和 Loader EXE 放在同一个目录下运行了)
  37:     //免去了将 DLL 复制到系统目录下的麻烦
  38:     string strDllPath = tmpArray;
  39:     strDllPath += DLLNAME;
  40:  
  41:     //将 DLL 的路径完整的复制到 remotePara 中
  42:     strcpy(remotePara.m_strDllPath, strDllPath.c_str());
  43:     //free(tmpArray);
  44:  
  45:     //在宿主进程中分配虚拟内存来容纳远程线程所需要的参数
  46:     PVOID pRemotePara = VirtualAllocEx(hProcess, NULL, sizeof(RemotePara), MEM_COMMIT, PAGE_READWRITE);
  47:     if(NULL == pRemotePara)
  48:     {
  49:         OutputErrorMessage("main - VirtualAllocEx Failed , Error Code Is %d , Error Message Is %s !");
  50:  
  51:         //释放 VirtualAllocEx 分配的内存
  52:         VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
  53:         CloseHandle(hProcess);
  54:     }

7. 将参数写入到 6 中在宿主进程中所分配的内存中,同样是调用 WriteProcessMemory 来完成;

   1: //将远程线程所携带的参数写入到宿主进程中所分配的虚拟内存
   2: if(NULL == WriteProcessMemory(hProcess, pRemotePara, &remotePara, sizeof(RemotePara), 0))
   3: {
   4:     OutputErrorMessage("main - WriteProcessMemory Failed , Error Code Is %d , Error Message Is %s !");
   5:  
   6:     //释放 VirtualAllocEx 分配的内存
   7:     VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
   8:     VirtualFreeEx(hProcess, pRemotePara, 0, MEM_RELEASE);
   9:     CloseHandle(hProcess);
  10: }

8. 调用 CreateRemoteThread 在 Explorer.exe(宿主进程)中创建远程线程;

   注意,当远程线程没有执行完时,不能够通过 VirtualFreeEx 来将远程进程中的内存释放掉,

   你想啊,我他妈的线程都还在 Explorer.exe 里面执行,你他妈的在外面把我占的内存给释放掉了,我还执行个屁啊 !

   所以这里调用了 WaitForSingleObject 来等待这个远程线程执行完毕,

   其执行完毕后再释放在 Explorer.exe 中所分配的存储空间 !

   这一部分的代码同上面的远程注入代码是类似的;

              

9. 编写好远程线程的线程处理例程即可;

   1: //=====================================================================================//
   2: //Name: bool RemoteThreadProc(LPVOID lpParameter)                                      //
   3: //                                                                                     //
   4: //Descripion: 远程线程处理例程                                                                 //
   5: //=====================================================================================//
   6: DWORD WINAPI RemoteThreadProc(PRemotePara pRemotePara)
   7: {
   8:     //对于从参数 pRemotePara 中传过来的 API 都需要重新声明
   9:     typedef HMODULE (WINAPI *LOADLIBRARY_ZACHARY)(LPCSTR);
  10:     typedef BOOL (WINAPI *FREELIBRARY_ZACHARY)(HMODULE);
  11:     typedef FARPROC (WINAPI *GETPROCADDRESS_ZACHARY)(HMODULE hModule, LPCSTR lpProcName);
  12:  
  13:     //这两个 API 是由 ZacharyDLL.dll 导出的,也需要重新声明
  14:     typedef void (* PRINTMESSAGEBOX_ZACHARY)();
  15:     typedef void (* PRINTDEBUGSTRING)();
  16:  
  17:     LOADLIBRARY_ZACHARY LoadLibrary_Zachary;
  18:     FREELIBRARY_ZACHARY FreeLibrary_Zachary;
  19:     GETPROCADDRESS_ZACHARY GetProcAddress_Zachary;
  20:     PRINTMESSAGEBOX_ZACHARY PrintMessageBox_Zachary;
  21:     PRINTDEBUGSTRING PrintDebugString_Zachary;
  22:  
  23:     //在参数 pRemotePara 中保存了 LoadLibray,FreeLibrary 和 GetProcAddress 这三个 API 的地址
  24:     LoadLibrary_Zachary = (LOADLIBRARY_ZACHARY)pRemotePara->m_dwLoadLibraryAddr;
  25:     FreeLibrary_Zachary = (FREELIBRARY_ZACHARY)pRemotePara->m_dwFreeLibraryAddr;
  26:     GetProcAddress_Zachary = (GETPROCADDRESS_ZACHARY)pRemotePara->m_dwGetProcAddrAddr;
  27:  
  28:     //获得 DLL 所在的地址
  29:     PCHAR pDllPath = pRemotePara->m_strDllPath;
  30:  
  31:     //加载我们自己的 DLL - ZacharyDLL.dll
  32:     HMODULE hMyDll = LoadLibrary_Zachary(pDllPath);
  33:  
  34:     if(NULL != hMyDll)
  35:     {
  36:         //从 ZacharyDll.dll 中通过 GetProcAddress 获取 DLL 导出的 API 的地址
  37:         PrintDebugString_Zachary = (PRINTDEBUGSTRING)GetProcAddress_Zachary(hMyDll, pRemotePara->m_printDbgStr);
  38:         PrintMessageBox_Zachary = (PRINTMESSAGEBOX_ZACHARY)GetProcAddress_Zachary(hMyDll, pRemotePara->m_printMsgBox);
  39:  
  40:         //执行 DLL 中所导出的 API
  41:         PrintDebugString_Zachary();
  42:         PrintMessageBox_Zachary();
  43:         //释放所加载的 DLL
  44:         FreeLibrary_Zachary(hMyDll);
  45:     }
  46:     return 0;
  47: }

10. 编写好要注入的 DLL – ZacharyDll.dll;

   1: BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
   2: {
   3:     switch (dwReason)
   4:     {
   5:     case DLL_PROCESS_ATTACH:
   6:         break;
   7:     case DLL_PROCESS_DETACH:
   8:         break;
   9:     case DLL_THREAD_ATTACH:
  10:         break;
  11:     case DLL_THREAD_DETACH:
  12:         break;
  13:     }
  14:  
  15:     return TRUE;
  16: }
  17:  
  18: //弹出一个对话框
  19: void PrintMessageBox()
  20: {
  21:     MessageBox(NULL, MESSAGE_CONTENT, MESSAGE_TITLE, MB_OK);
  22: }
  23:  
  24: //打印语句
  25: void PrintDebugString()
  26: {
  27:     //直接打印出 5 条同样的消息
  28:     for(int i=0; i<5; i++)
  29:     {
  30:         OutputDebugString("In ZacharyDll - PrintDebugString !");
  31:     }
  32: }

                

                

两种注入技术的优点和缺点总结

                

使用代码远程注入技术的话,其相对于使用 DLL 远程注入技术来说,

有一个优点,就是其不会无缘无故的让宿主进程加载其他的 DLL,

为什么说这是一个优点 ? 那是因为很多的监控软件或者杀软都在实时监控着每个进程,

当一个进程中加载了其他的 DLL 时(加载 DLL 的动作相对来说是比较大的)很容易被发觉,

而且当一个 DLL 被加载到进程中以后,可以利用很多的工具,

比如 Process Explorer 之类的将该进程所加载的 DLL 枚举出来,这样你所注入的 DLL 也就暴露无遗了 !

而如果你使用的是代码注入,那相对来说会安静很多(毕竟是小动作),而且也不会让宿主进程加载其他的 DLL,

所以相对来说,其成功的可能性会更高,但是使用代码远程注入有一个致命的弱点,

那就是你所注入的代码中所使用的 API 都必须要重定向,

而且如果是自定义的函数的话,则必须将这个函数也全部拷贝到宿主进程中,

注入的代码中所使用的全局变量以及所使用的字符串都必须重新拷贝到宿主进程中,

听起来貌似没什么,但是事实上,这屁东西会搞得很复杂,就比如你在注入的代码中所使用的一个字符串,

你也必须先在宿主进程中分配虚拟内存,然后将这个字符串写入到这个新分配的虚拟内存中,

如果你字符串多的话,这样的操作会烦死人去,而且这还仅仅是字符串,对于你所需要使用的一些 Win32 API,

你也都得先获取好这些 API 的地址,然后又重复上面的操作,分配虚拟内存,写入地址,最后才能够在远程线程中调用,

所以如果你所注入的代码需要完成很复杂的功能的话,还是使用 DLL 的远程注入技术比较好,使用远程注入代码会搞死人的 !

                     

使用 DLL 的远程注入技术的病毒或者木马通常都位于一个 DLL 中,

在系统启动时,通过另外的一个 EXE 程序来在另外的一个进程(宿主进程,比如使用 Explorer.exe)中创建一个远程线程,

然后再在这个远程线程的线程处理函数中将这个带有病毒或者木马主体的 DLL 加载到宿主进程中,

这样的话,这个带有病毒或者木马主体的 DLL 就会被宿主进程加载,从而得以在宿主进程中执行,

这样,即使我们自己的 EXE(这个进程通常被称之为 Loader)进程被关闭了也不会影响到病毒或者木马主体代码的执行,

因为这些主体代码位于 Explorer.exe 进程中执行,而 Explorer.exe 基本上不会被关闭的。

并且使用这种方法,你的恶意代码也很难被什么任务管理器之类的发现,因为只要宿主进程没有终止运行,

那么这个 DLL 也就不会在内存中卸载(当然被卸载还是可能的,杀软就可以利用这点来将这个 DLL 卸载掉)。

     

         

Demo 展望:

            

上面的这种注入技术用来实现木马或者其他的恶意程序其实是比较方便的,

首先由一个 Loader.exe (这个 Loader 可以通过其他的方式来设置为随机器自动启动,

这可以通过修改 system.ini 或者注册表或者服务之类的来实现)

来通过 CreateRemoteThread 来在 Explorer.exe 进程中创建一个远程线程,

而后由这个远程线程神不知鬼不觉的调用一个另外的 DLL,

然后在另外的那个 DLL 中,我们就可以做很多的事情了啊,比如最简单的,设个全局键盘钩子,用来捕获键盘的记录,

再进行一定的解析就有可能获取用户有效的密码之类的信息,同时,既然 DLL 都注入到 Explorer.exe 中了,

那么还可以做很多邪恶的事情,比如在其中悄悄的扫描用户磁盘上的文件,只要是 .jpg, .png 之类的就全部给记录下来,

或者再在 DLL 中创建个什么 SOCKET 之类的,并且将这些什么 .png 啊,.jpg 啊之类的图片数据悄悄的传出去,

然后说不准第二个艳照门就出来了 ~

当然这些都是后话了,不过有了上面的这几个技术,要实现这种简单的木马功能还是很容易了哦 !

当然,这里再提一下的是,这样做不道德 ! 针对女朋友的属于合法行为 ! 哈哈哈 !

然后还有一个要提一下的是,现在这种注入方式,杀软或者安全卫士是能够捕捉到了,也就是过不了杀软或安全卫士这一关了哦 !

毕竟 03 年就有大牛弄这种东西了,这么些年了,人家做反病毒做安全的也不是吃饭的 !

不过如果将上面的技术和 Rootkit 做个结合,可能效果会很不一样了哦,尚待研究 ~

恶意代码分析实战 9 隐蔽的恶意代码启动
农夫果园好好喝的博客
01-24 1580
查看程的导入函数。通过这几个函数,可以推断出是远程线程注入。使用ProMon检测,并没有看到什么有用的信息。使用Proexproer检查。也没有什么有用的信息。拖入IDA分析一下。将这几个字符串重命名,便于识别。该程是一个对于PID的遍历。这个函数的作用是检查是否存在explorer.exe这个程。Buffer表示的字符串是Lab12-01.dll.这段代码所表示的就是对explorer.exe进行注入
向日葵远程协助无法开启黑屏
最新发布
Friest_的博客
04-10 2032
拦截补充描述:程正在进行远程线程注入,将代码藏匿到其他进程来运行,木马通常以此来隐藏自己的恶意行为。解决方法:已信任区加入风险文件C:\Windows\TEMP\Oray\SunloginClient\privacy.dll即可。风险文件:C:\Windows\TEMP\Oray\SunloginClient\privacy.dll。进程:C:\Windows\System32\rundll32.exe。路径:C:\Windows\System32\dwm.exe。所以还是想调试一下看看哪里出了问题。
CreateRemoteThread函数多参数传入使用方法
指月的手指,成不了月亮,更得不到月亮!!
11-14 6953
注意事项: 1.Debug版本编译的时候使用增量编译,导致每个函数都是用一个Thunk, 所以请使用Release版本。 2.目标进程非本进程时不能调用本进程内的函数或使用本进程内的变量,有时在隐式使用时可能会引起该 问题,容易引起进程崩溃。(例如WriteProcessMemory写入的函数调用了本进程的全局变量) 3.多参数使用时请在目标进程为函数参数分配相应的内存空间,因为C
Win7 CreateRemoteThread 另类使用方法
热门推荐
Koma的主页
05-31 2万+
同样的代码,在XP下面随便你怎么整,WIN7的话是相当纠结的,具体哪些错误就不解释了~~
注入 - 代码注入远程线程 - C_C++_Python_Java - 博客园.pdf
06-17
注入 - 代码注入远程线程 - C_C++_Python_Java - 博客园.pdf
InjectDLL代码 实现远程注入线程.zip
03-28
InjectDLL代码 实现远程线程注入.zip
C#版DLL远程线程注入代码
01-21
C#没有自动调用WIN32的一些API函数,我们可以手动添加内核库到我们自己的代码,从而实现调用...此方法不仅仅用于远程线程注入,还可以用于从MFC转C#过程不知道如何用C#实现功能,但有知道如何用MFC实现功能的方法。
远程线程注入_远程_远程线程_dll注入_注入_
10-01
创建远程线程注入目标进程dll详情代码有注释
使用远程线程注入DLL
08-04
远程线程注入,含代码。 详细介绍远程线程注入,并且包含完整代码远程线程注入,含代码。 详细介绍远程线程注入,并且包含完整代码
exe将dll注入explorer.exe资源管理器进程_DLL注入示例.injectdll
03-28
exe将dll注入explorer.exe资源管理器进程_DLL注入示例.zip
将dll注入到资源管理器explorer.exe
01-02
将dll注入到资源管理器explorer.exe
远程线程注入实现木马进程隐藏
05-05
通过远程线程注入技术实现木马进程隐藏,内附有完整地代码以及详细的说明文档
DLL注入创建远程线程
m0_51713041的博客
04-09 1059
DLL注入 一:概念 1.dll注入是指向运行的其它进程强制插入特定的dll文件。从技术细节来说,DLL注入命令其他进程自行调用LoadLibrary() API,加载用户指定的dll文件。 2.当dll被加载到进程以后,就拥有了访问进程内存的权限。(用户可以通过这个来修复程bug或增加功能等)。 3.dll被加载到进程后会自动运行DllMain函数。 4. 使用LoadLibrary() API加载某个DLL时,该DLL的DllMain函数就会被自动执行。DLL注入的工作原理就是从外部促使目标进程
远程线程注入 CreateRemoteThread 返回NULL
weixin_34266504的博客
02-05 492
在win10下测试成功的代码,在win7下CreateRemoteThread竟然返回0 GetLastError 返回 5 [拒绝访问] 调用OpenProcess是提供的参数 PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION 想了半天没明白为啥拒绝访问,只好暴力解决 我的解决方案 :提供给OpenProces...
CreateRemoteThread_远程CALL调用代码实现原理。
02-02 2568
各位亲爱的朋友: 我们又在第11款VIP课程相会了,那么,这节课,我将与您分享远程CALL调用代码实现原理。 编程思路:编程的话您只需要编写一次,了解到编写的效果,以后想要这种功能效果都是这么编写。对编写的代码越熟悉,就越容易延伸它与修改它。 具体编写技巧: 源码借箭:13.赞!VC++如何调试出代码异常错误地方。 CreateRemoteThread 创建一个在其它进程地址空间运行的线程 HA
java远程线程注入_系统权限远程线程注入Explorer.exe
weixin_39594895的博客
02-17 135
提升为系统权限,注入explorer一丶简介我们上一面说了系统服务拥有系统权限.并且拥有system权限.还尝试启动了一个进程.那么我们是不是可以做点坏事了.我们有一个系统权限进程.而调用 CreateRemoteThread可以创建远程线程,是否可以注入到我们桌面资源管理器当那.答案是可以的.我也试过提权的方式注入.可惜都是拒绝访问.所以我提升为system权限(系统服务,创建的我们进程就...
注入Explorer.exe 并Hook CreateProcessW (MinHook库)
Care
01-21 3247
记录下学习的经历.. win10系统 被某杀毒给挂钩了.. 直接用虚拟机来操作 // dllmain.cpp : 定义 DLL 应用程的入口点。 #include "stdafx.h" #include #include "MinHook.h" #include #if defined _M_X64 #pragma comment(lib, "libMinHoo
我是一个explorer线程
fanshaoxuan的专栏
11-28 188
伴随着一记电流响声,天逐渐亮了,不到一会儿太阳就升起来了,熟悉的蓝天白云和草地再次出现,今天又是繁忙的一天。 我是explorer公司的一个工作人员:一个普通的线程。我们公司就是人类看到的explorer.exe进程,公司的业务主要是提供可视化的图形界面,让人类来操作电脑,我负责的事情是桌面窗口的消息处理,隔壁工位小薇妹子负责的是任务栏窗口消息处理。我们国家是一个Windows体制的国家,有...
写一段远程线程注入代码的例子
03-12
以下是一段远程线程注入代码的例子: ``` #include #include DWORD GetProcessIdByName(const wchar_t* processName) { DWORD processId = 0; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS...

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • Matlab图像处理入门教程(菜鸟级) 37860
  • JQuery实现局部页面动态刷新 22797
  • void InitStack( SqStack *&S) 21307
  • 海明码 13889
  • Linux终端得到root权限 10377

分类专栏

  • 多媒体
  • web 9篇
  • =========编程=======
  • 杂谈 3篇
  • 算法 69篇
  • VC 14篇
  • 数字图像处理
  • ==============================
  • linux 4篇
  • 数据库 1篇
  • JAVA 2篇

最新评论

  • JQuery实现局部页面动态刷新

    ༄迷恋࿐: 可以,注意如果写成 [code=html] $('.div_menu').load(location.href+' .div_menu'); [/code] 的话,注意[code=html] +' .div_menu'这里多一个空格,不然不行 [/code]

  • Matlab图像处理入门教程(菜鸟级)

    四次方路引: 请问一下,怎么能将图片从长方形转变为扇形或者其他形状啊?

  • 海明码

    牛了个牛: 请问为什么生成海明码的时候p1在最右边,检验海明码的时候p1却在最左边

  • long long 与int的区别

    m0_61603125: 天我做一道题的时候发现用int的时候数据会溢出,用long long就不会。于是我想看一下long long 到底可以存多大的数,在devc里我对long long i=10000000000;的时候可以,但不能比这大了,再然后我发现int也有这么大。我纳闷了,怎么会出现这种情况?long long和int到底区别在哪里? long long是64bit存储的,而int只有32bit 赋初始值的时候,虽然直接写long long i=10000000000也可以 但程序处理的时候会先将10000000000变为int再赋值 一般long long初值是大数的话,是需要写成long long i=10000000000LL的~ 追问: 再请问一下,longlong型的数组怎么输出? 追答: %lld

  • 海明码

    hvang1988: 对的 9意思是从右向左第9个数 可参考5-2图中第一行,为什么是9,10,11参考5-2图中第6行p4。 9对应的值是1,10是1,11是0 所以 1 xor 1 xor 0 =0。异或俗称半加法,除1+1=0其他同加法。

大家在看

  • Oracle中先进先出数据结构的例子
  • 【每日一练】python入门之函数基础用法
  • 如何将一个属性绑定到 Kivy 中的另一个属性? 97
  • 大型ERP设计-业务与功能指引:外币折算与辅助账套 365
  • 前端冲刺必备指南

最新文章

  • 48种字体特效
  • JQuery实现局部页面动态刷新
  • SSM框架Exception
2022年1篇
2018年5篇
2017年11篇
2016年23篇
2015年69篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

哆哆女性网糕点起名你图不要轻易说不食梦貘哪里多我想网上起名徐姓女孩起名100分燕子的拼音清蒸鳜鱼的做法明星直播用什么软件夏洛特烦恼演员表西方世界的劫难3攻略起名的 易经三兄弟起名随身仙府的属猴人起名宜什么8画有什么字起名砂石料公司起什么名字2021免费八字起名周易海运公司起名起个艺名大全男生性崔男孩子的起名大全只管向前奔跑阅读答案起名常见笔画鬼作属牛什么宝宝起名我的老千生涯全集范冰冰马震扫黄先锋演员表女孩用奕字起名好不好披荆斩棘的哥哥免费观看淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻不负春光新的一天从800个哈欠开始有个姐真把千机伞做出来了国产伟哥去年销售近13亿充个话费竟沦为间接洗钱工具重庆警方辟谣“男子杀人焚尸”男子给前妻转账 现任妻子起诉要回春分繁花正当时呼北高速交通事故已致14人死亡杨洋拄拐现身医院月嫂回应掌掴婴儿是在赶虫子男孩疑遭霸凌 家长讨说法被踢出群因自嘲式简历走红的教授更新简介网友建议重庆地铁不准乘客携带菜筐清明节放假3天调休1天郑州一火锅店爆改成麻辣烫店19岁小伙救下5人后溺亡 多方发声两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#青海通报栏杆断裂小学生跌落住进ICU代拍被何赛飞拿着魔杖追着打315晚会后胖东来又人满为患了当地回应沈阳致3死车祸车主疑毒驾武汉大学樱花即将进入盛花期张立群任西安交通大学校长为江西彩礼“减负”的“试婚人”网友洛杉矶偶遇贾玲倪萍分享减重40斤方法男孩8年未见母亲被告知被遗忘小米汽车超级工厂正式揭幕周杰伦一审败诉网易特朗普谈“凯特王妃P图照”考生莫言也上北大硕士复试名单了妈妈回应孩子在校撞护栏坠楼恒大被罚41.75亿到底怎么缴男子持台球杆殴打2名女店员被抓校方回应护栏损坏小学生课间坠楼外国人感慨凌晨的中国很安全火箭最近9战8胜1负王树国3次鞠躬告别西交大师生房客欠租失踪 房东直发愁萧美琴窜访捷克 外交部回应山西省委原副书记商黎光被逮捕阿根廷将发行1万与2万面值的纸币英国王室又一合照被质疑P图男子被猫抓伤后确诊“猫抓病”

哆哆女性网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化