• DLL注入:远程线程注入


    Dll 代码:

    #include "stdafx.h"
    #include <iostream>
    #include <Windows.h>
    #include <tlhelp32.h>
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
    					 )
    {
    	switch (ul_reason_for_call)
    	{
    	case DLL_PROCESS_ATTACH:
    		MessageBox(NULL,L"DLL_PROCESS_ATTACH",L"LYSM",NULL);
    		break;
    	case DLL_THREAD_ATTACH:
    	case DLL_THREAD_DETACH:
    	case DLL_PROCESS_DETACH:
    		break;
    	}
    	return TRUE;
    }
    

    注入器代码:

    #include "stdafx.h"
    #include<stdio.h>
    #include<Windows.h>
    #include<TlHelp32.h>
    #include <iostream>
    
    using namespace std;
    
    // 进程名查PID
    DWORD getProcessHandle(LPCTSTR lpProcessName)
    {
        HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    	PROCESSENTRY32 process = {sizeof(PROCESSENTRY32)};
    	
    	while (Process32Next(hProcessSnap,&process))
    	{
    		if(strcmp(process.szExeFile, lpProcessName) == 0){return process.th32ProcessID;}
    	}
    
    	cout << "没有找到进程" << endl;
    	return 0;
    }
    
    int main(int argc,char *argv[])
    {
    	
    	// 初始化
        DWORD dwpid = getProcessHandle("Injector.exe");
        LPCSTR lpDllName = "E:\MyFiles\Programing\vs2012\MyPrograms\Test_Dll\Debug\Test_Dll.dll";
    
        // 取 Injector.exe 句柄
        HANDLE hProcess = OpenProcess(
    		PROCESS_ALL_ACCESS,		// 所有权限
    		FALSE,					// 进程不继承句柄
    		dwpid					// PID
    		);
    	if(!hProcess){cout << "OpenProcess 失败: " << GetLastError() << endl;}
    
    	// 为 dll 分配内存,并记录基地址
        DWORD dwSize = strlen(lpDllName)+1;	
        LPVOID lpRemoteBuf = VirtualAllocEx(
    		hProcess,			// 进程句柄
    		NULL,				// 分配的起始地址
    		dwSize,				// 分配的区域大小
    		MEM_COMMIT,			// 类型,MEM_COMMIT:分配内存
    		PAGE_READWRITE		// 内存保护属性,PAGE_READWRITE:可读可写
    		);
    
    	// 写入内存
    	if(!WriteProcessMemory(
    		hProcess,			// 进程句柄
    		lpRemoteBuf,		// dll 基地址指针
    		lpDllName,			// 写入内容的缓冲区指针
    		dwSize,				// 缓冲区字节大小
    		NULL				// 接收实际写入的字节数
    		))
    	{cout << "WriteProcessMemory 失败:" << GetLastError() << endl;}
        
    	// 创建远程线程
        HANDLE hNewRemoteThread = CreateRemoteThread(
    		hProcess,								// 进程句柄
    		NULL,									// 默认安全描述符,不继承句柄
    		NULL,									// 默认的堆栈初始大小
    		(LPTHREAD_START_ROUTINE)LoadLibraryA,	// 远程线程起始地址
    		lpRemoteBuf,							// 线程函数基地址指针
    		NULL,									// 线程在创建之后立即运行
    		NULL									// 不返回线程标识符
    		);
        if(!hNewRemoteThread){cout << "CreateRemoteThread 失败:" << GetLastError() << endl;}
    
        // 等待线程句柄返回
        WaitForSingleObject(
    		hNewRemoteThread,	// 线程句柄
    		INFINITE			// 超时时间,INFINITE:不返回则一直等待				
    		);
    
    	// 关闭线程句柄
        CloseHandle(hNewRemoteThread);
    
    
        getchar();
        return 0; 
    }
    

    此处为 32 位程序,所以注入 64 位进程会失败!

    64 位注入,参考

    int main()
     {
         BOOL bFlag = FALSE;
     
         char *szDllName = "MSGDLL.dll";
         //bFlag = EnablePrivilege(SE_DEBUG_NAME);    //返回值为1时代表成功
     
         //得到目标进程句柄
         HANDLE hDestProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, );
     
         LPTHREAD_START_ROUTINE dwAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");
     
         //在目标进程的地址空间内分配一个内存块
         LPVOID pRemoteSpace = VirtualAllocEx(hDestProcess, NULL, strlen(szDllName) + , MEM_COMMIT,
             PAGE_READWRITE);
     
         //向上一步的内存块中写入数据,就是要加载的DLL名字
         bFlag = WriteProcessMemory(hDestProcess, pRemoteSpace, szDllName, strlen(szDllName) + , );
     
         //在目标进程内创建线程,线程的入口函数就是LoadLibraryA, 参数就是Dll名字
         HANDLE hThread = CreateRemoteThread(hDestProcess, NULL, , dwAddr, pRemoteSpace,
             NULL,
         );      //前面都是成功的,就到了这一步,返回的错误是5,Access denied,权限不够
                 //本来以为我的VS是以管理员权限启动的,那么我这个进程应该权限就都够了,
                 //看来不行,必须程序提权
                 //我提权了之后,发现还是不行,之后上网查了
                 //发现是32位注入到64位中会有问题,所以我换了个x64,然后显然线程运行成功了,
                 //但是现在远程进程却崩溃了,估计是DLL是32的,我换个DLL编译方式再试试
                 //我编译了64位的DLL,然后还是崩溃的,之后我发现了应该是我函数地址传的有问题
                 //因为32位的LoadLibraryA地址是DWORD,但64位却是ULONGLONG,所以仅仅改变编译方式还不够
                 //必须用一个足够容纳8个字节地址的类型来保存,这样就够了
     
                 //另外一个需要注意的问题就是,为什么我在我这个进程中得到的LoadLibrary在远程进程中也可以用
                 //答案就是,系统DLL在各个进程中的映射地址都是一样的,不过具体情况具体分析,至少这个函数看来是一样的。
     
                 //在我完成了之后,我把EnablePrivileges这行注释掉了,但仍然注入成功,看来我用管理员权限运行VS2015之后就够了
     
                 //然后我又发现了一个问题,就是对同一个进程,加载dll只能一次,第二次就不会弹了
                 //原因,我目测是,DLL已经被加载了,所以第二次就不加载了,也就不执行DllMain那个函数了
                 //除非我创建一个线程再UnLoad那个LIB,之后再LOAD,这样应该就可以了
                 //也可以换个Dll名字,再LOAD, 反正方法很多。
     
         DWORD dwErr = GetLastError();
     
         return ;
     }
    

    注入器

     //DLL的代码,用DLL方式生成一下,拉到前面EXE目录,或者系统目录都行,跟前面代码中DLL名字有没有加绝对路径有关
    //这代码是书上的代码,直接复制了
    /* ************************************
    *《精通Windows API》
    * 示例代码
    * msg.c
    * 6.5  动态链接库
    **************************************/
    /* 头文件 */
    #include <Windows.h>
    #include <Psapi.h>
    /* 链接 */
    #pragma comment (lib, "Psapi.lib")
    /* 函数声明 */
     
    // 使用__declspec(dllexport)声明导出函数
    __declspec(dllexport) DWORD ExportExample(LPSTR szMsg, DWORD dwCode);
     
    /*************************************
    * DllMain
    **************************************/
    BOOL WINAPI DllMain(
        HINSTANCE hinstDLL,  // DLL模块的句柄
        DWORD fdwReason,     // 调用的情况
        LPVOID lpReserved)  // reserved
    {
        // 在不同的情况下都会调用DllMain函数,分别处理
        switch (fdwReason)
        {
            // 加载Dll
            case DLL_PROCESS_ATTACH:
                {
                    CHAR lpMainMoudleName[MAX_PATH];
                    CHAR lpMessage[MAX_PATH + ];
                    // 获取PID 和主模块名,将弹出消息框
                    DWORD dwPID = GetCurrentProcessId();
                    GetModuleBaseName(GetCurrentProcess(), NULL, lpMainMoudleName, MAX_PATH);
                    wsprintf(lpMessage, "Process name: %s, PID: %u ", lpMainMoudleName, dwPID);
                    MessageBox(NULL, lpMessage, "msg.dll", MB_OK);
                    break;
                }
                // 新建线程
            case DLL_THREAD_ATTACH:
                break;
                // 线程退出
            case DLL_THREAD_DETACH:
                break;
                // 释放Dll
            case DLL_PROCESS_DETACH:
     
                break;
        }
        return TRUE;
    }
     
    /*************************************
    * DWORD ExportExample(LPSTR szMsg, DWORD dwCode)
    * 功能    导出函数,显示消息
    *
    * 参数    LPSTR szMsg    字符串; DWORD dwCode 整形
    **************************************/
    DWORD ExportExample(LPSTR szMsg, DWORD dwCode)
    {
        LPVOID lpShowOut = HeapAlloc(GetProcessHeap(), , lstrlen(szMsg) + );
        wsprintf((LPSTR)lpShowOut, "%s,%d", szMsg, dwCode);
        MessageBox(NULL, (LPSTR)lpShowOut, "由导出函数弹出的消息!", MB_OK);
        HeapFree(GetProcessHeap(), , lpShowOut);
        return ;
    }
    

    需要注意的点都在那一大串注释中

    64位进程,就得用64位的EXE来CreateRemoteThread, 另外DLL也应该是64位

    32位进程,就得用32位的EXE来CreateRemoteThread, 另外DLL也应该是32位

    把CreateRemoteThread的入口点函数设为LoadLibraryA(W),线程的那个参数设为DLL路径指针(在目标进程中,所以得把DLL路径拷到目标进程 中, 用VirtualAllocEx在目标进程中分配块空间,然后WriteProcessMemory).

    这样可行的原因:

    线程的函数原型DWORD ThreadProc(LPVOID lpParam)

    LoadLibrary的函数原型HMODULE LoadLibrary(LPCTSTR lpFileName);

    其实是一样的,指针都是同样大小,都只有一个参数,返回值无所谓..

    另外在目标进程和本进程中LoadLibraryA(W)的虚拟地址是一样的..


    许可协议: 文章中的代码均为学习时整理的笔记,博客中除去明确标注有参考文献的文章,其他文章【均为原创】作品,转载请务必【添加出处】,您添加出处是我创作的动力!
  • 相关阅读:
    Synchronized 在 java 中的用法
    ExtJS写的小系统,有源码,献给刚入门的朋友。
    轻松实现Apache,Tomcat集群和负载均衡
    dbms_stats使用(转)
    Java关键字final、static使用总结
    java参数传递总结
    持久化上下文的传播
    主题:Spring Security 2 配置精讲
    Tomcat中web.xml文件的详细说明
    如何学习Ext
  • 原文地址:https://www.cnblogs.com/LyShark/p/15018764.html
Copyright © 2020-2023  润新知