首页
论坛
课程
招聘
[原创][原创]dll注入&代码注入 学习总结
2021-9-17 20:18 20706

[原创][原创]dll注入&代码注入 学习总结

2021-9-17 20:18
20706

dll注入&代码注入

CreateRemoteThread

思路:在目标进程中申请一块内存并向其中写DLL路径,然后调用 CreateRemoteThread ,(在自己进程中 创建远程线程到到目标进程)在目标进程中创建一个线程。LoadLibrary()”函数作为线程的启动函数,来加载待注入的DLL文件 ,LoadLibrary()参数 就是存放DLL路径的内存指针. 这时需要目标进程的4个权限(PROCESS_CREATE_THREAD,PROCESS_QUERY_INFORMATION,PROCESS_VM_OPERATION,PROCESS_VM_WRITE)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    //计算DLL路径名所需的字节数
    DWORD dwSize = (lstrlenW(pszLibFile) + 1) * sizeof(wchar_t);
 
    // 获取传递进程ID的进程句柄
    HANDLE hProcess = OpenProcess(
        PROCESS_QUERY_INFORMATION |
        PROCESS_CREATE_THREAD |
        PROCESS_VM_OPERATION |
        PROCESS_VM_WRITE,//目标进程的四个权限
        FALSE, dwProcessId);
 
    // 在远程进程中为路径名分配空间
    LPVOID pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
 
 
    // 将DLL的路径名复制到远程进程地址空间
    //pszLibFile:要注入的dll的路径  pathname
    DWORD n = WriteProcessMemory(hProcess, pszLibFileRemote, (PVOID)pszLibFile, dwSize, NULL);
 
    //在Kernel32.dll中获取LoadLibraryW的实际地址
    PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
 
 
    //创建一个调用LoadLibraryW(DLLPathname)的远程线程
    // CreateRemoteThread(目标进程句柄,NULL,0,线程函数指针,线程函数参数,0,NULL)
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);
 
 
    // 等待远程线程终止
    WaitForSingleObject(hThread, INFINITE);
 
    // 释放包含DLL路径名的远程内存并关闭句柄
    if (pszLibFileRemote != NULL) //开辟的内存已经注入进数据
        VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);
    //关闭线程和进程函数句柄
    if (hThread != NULL)
        CloseHandle(hThread);
 
    if (hProcess != NULL)
        CloseHandle(hProcess);
 
    return(0);
}

RtlCreateUserThread

RtlCreateUserThread()”调用“NtCreateThreadEx(),这意味着“RtlCreateUserThread()”是“NtCreateThreadEx()”的一个小型封装函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
 
 
    LPVOID LoadLibraryAddress = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
 
 
    RtlCreateUserThread = (pRtlCreateUserThread)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlCreateUserThread");
 
 
#ifdef _DEBUG
    wprintf(TEXT("[+] Found at 0x%08x\n"), (UINT)RtlCreateUserThread);
    wprintf(TEXT("[+] Found at 0x%08x\n"), (UINT)LoadLibraryAddress);
#endif
 
    DWORD dwSize = (wcslen(pszLibFile) + 1) * sizeof(wchar_t);
 
    LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 
 
    BOOL bStatus = WriteProcessMemory(hProcess, lpBaseAddress, pszLibFile, dwSize, NULL);
 
 
    bStatus = (BOOL)RtlCreateUserThread(
        hProcess,
        NULL,
        0,
        0,
        0,
        0,
        LoadLibraryAddress,
        lpBaseAddress,
        &hRemoteThread,
        NULL);
    if (bStatus < 0)
    {
        wprintf(TEXT("[-] Error: RtlCreateUserThread failed\n"));
        return(1);
    }
    else
    {
        wprintf(TEXT("[+] Remote thread has been created successfully ...\n"));
        WaitForSingleObject(hRemoteThread, INFINITE);
 
        CloseHandle(hProcess);
        VirtualFreeEx(hProcess, lpBaseAddress, dwSize, MEM_RELEASE);
        return(0);
    }
 
    return(0);
}

总结:

 

openprocess 获得目标进程句柄

 

getprocaddress 获得loadlibrary地址

 

getprocaddress 获得RtlCreateUserThread地址

 

获得dll文件==路径==大小

 

virtualalloc 在目标进程中开辟路径大小的空间

 

writeprocess写dll路径名进内存

 

bStatus = (BOOL)RtlCreateUserThread(
hProcess,
NULL,
0,
0,
0,
0,
LoadLibraryAddress,
lpBaseAddress, 存有dll路径的内存地址 指针类型
&hRemoteThread,
NULL);

NtCreateThreadEx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    memset(&ntbuffer, 0, sizeof(NtCreateThreadExBuffer));
 
    DWORD dwSize = (lstrlenW(pszLibFile) + 1) * sizeof(wchar_t);
 
    HANDLE hProcess = OpenProcess(
        PROCESS_QUERY_INFORMATION |
        PROCESS_CREATE_THREAD |
        PROCESS_VM_OPERATION |
        PROCESS_VM_WRITE,
        FALSE, dwProcessId);
 
 
    LPVOID pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
 
 
    int n = WriteProcessMemory(hProcess, pszLibFileRemote, (LPVOID)pszLibFile, dwSize, NULL);
 
 
    PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
 
    PTHREAD_START_ROUTINE ntCreateThreadExAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtCreateThreadEx");
 
 
    if (ntCreateThreadExAddr)
    {
        ntbuffer.Size = sizeof(struct NtCreateThreadExBuffer);
        ntbuffer.Unknown1 = 0x10003;
        ntbuffer.Unknown2 = 0x8;
        ntbuffer.Unknown3 = (DWORD*)&dwTmp2;
        ntbuffer.Unknown4 = 0;
        ntbuffer.Unknown5 = 0x10004;
        ntbuffer.Unknown6 = 4;
        ntbuffer.Unknown7 = (DWORD*)&dwTmp1;
        ntbuffer.Unknown8 = 0;
 
        LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx)ntCreateThreadExAddr;
 
        NTSTATUS status = funNtCreateThreadEx(
            &hRemoteThread,
            0x1FFFFF,
            NULL,
            hProcess,
            pfnThreadRtn,
            (LPVOID)pszLibFileRemote,
            FALSE,
            NULL,
            NULL,
            NULL,
            &ntbuffer //这里原来是NULL,但是跑的时候也可以注入,懵逼
            );
 
#ifdef _DEBUG
        wprintf(TEXT("[+] Status: %s\n"), status);
#endif
        if (status != NULL)        // FIXME: always returns NULL even when it suceeds. Go figure.
        {
            wprintf(TEXT("[-] NtCreateThreadEx Failed! [%d][%08x]\n"), GetLastError(), status);
            return(1);
        }
        else
        {
            wprintf(TEXT("[+] Success: DLL injected via NtCreateThreadEx().\n"));
            WaitForSingleObject(hRemoteThread, INFINITE);
        }
    }
 
    if (pszLibFileRemote != NULL)
        VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);
 
    if (hRemoteThread != NULL)
        CloseHandle(hRemoteThread);
 
    if (hProcess != NULL)
        CloseHandle(hProcess);
 
    return(0);
}

总结:openprocess 获得目标进程句柄

 

getprocaddress 获得loadlibrary地址

 

getprocaddress 获得NtCreateThreadEx地址

 

获得dll文件==路径==大小

 

virtualalloc 在目标进程中开辟路径大小的空间

 

writeprocess写dll路径名进内存

 

利用NtCreateThreadEx 进行 dll注入

 

以上三种远程线程注入函数的区别:

 

CreateRemoteThread 和RtlCreateUserThread都调用 NtCreateThreadEx创建线程实体

 

RtlCreateUserThread不需要csrss验证登记 需要自己结束自己 而CreateRemoteThread 不一样,不用自己结束自己。

 

线程函数不由createthread执行 而是kernal32!baseThreadStart 或者 kernal32!baseThreadInitThunk 执行,结束后 还会调用 exitthread 和 rtlexituserthread 结束线程自身 。

ZwCreateThreadEx

同理,与CreateRemoteThread或RtlCreateUserThread或NtCreateThreadEx用法类似,也是创建远程线程实现注入

反射式dll注入

在别人的内存里调用自己编写的dll导出函数 ,自己dll导出函数里实现自我加载(加载PE的整个过程),少了使用LoadLibrary的过程。

 

反射式注入方式并没有通过LoadLibrary等API来完成DLL的装载,DLL并没有在操作系统中”注册”自己的存在,因此ProcessExplorer等软件也无法检测出进程加载了该DLL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//LoadRemoteLibraryR 函数说明
extern "C" HANDLE __stdcall LoadRemoteLibraryR(HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter);
 
DWORD demoReflectiveDllInjection(PCWSTR cpDllFile, DWORD dwProcessId)
{
    HANDLE hFile = NULL;//创建的dll文件句柄
    HANDLE hModule = NULL;//开辟的堆空间句柄
    HANDLE hProcess = NULL;//目标进程句柄
    LPVOID lpBuffer = NULL;
    DWORD dwLength = 0;
    DWORD dwBytesRead = 0;
 
    do
    {
        hFile = CreateFileW(cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
 
        dwLength = GetFileSize(hFile, NULL);
 
 
#ifdef _DEBUG
        wprintf(TEXT("[+] File Size: %d\n"), dwLength);
#endif
        //为dll文件开辟堆空间 !!!!!!!!这是在自己的进程内存中  分配堆内存
        lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
 
        //将dll文件读进开辟的堆空间中 hfile--》lpbuffer
        if (ReadFile(hFile, lpBuffer, dwLength, &dwBytesRead, NULL) == FALSE) BREAK_WITH_ERROR("[-] Failed to alloc a buffer!");
        //获得目标进程的句柄
        hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId);
 
        // LoadRemoteLibraryR:在dll模块加载到内存时获取入口点,并且实现调用该函数(采用rtlcreateuserthread的方式)远程线程注入
 
 
 
 
        hModule = LoadRemoteLibraryR(hProcess, lpBuffer, dwLength, NULL);
 
 
        WaitForSingleObject(hModule, -1);
 
    } while (0);
 
    //注入完毕,释放堆空间,关闭进程句柄
    if (lpBuffer) HeapFree(GetProcessHeap(), 0, lpBuffer);
 
    if (hProcess) CloseHandle(hProcess);
 
    return 0;
}

LoadRemoteLibraryR核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
            //检查库是否有ReflectiveLoader
 
            // 获得dll文件的入口点偏移
            dwReflectiveLoaderOffset = GetReflectiveLoaderOffset(lpBuffer);//lpbuffer:堆内存的指针 指向存有dll文件的堆内存空间
 
 
            // alloc memory (RWX) in the host process for the image...
            //为映像分配内存
            lpRemoteLibraryBuffer = VirtualAllocEx(hProcess, NULL, dwLength, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 
 
            // write the image into the host process...
            //将映像写入目标进程
 
 
            /*
            BOOL WriteProcessMemory(
            HANDLE hProcess,
                LPVOID lpBaseAddress, 要写的内存首地址
                LPVOID lpBuffer, 指向要写的数据的指针
                DWORD nSize,
                LPDWORD lpNumberOfBytesWritten
                );
                */
 
                //将映像写入目标进程  lpRemoteLibraryBuffer  在目标进程中分配的内存空间 lpBuffer在该进程内存空间中分配的堆内存
 
 
            // add the offset to ReflectiveLoader() to the remote library address...
            //lpRemoteLibraryBuffer 分配的内存地址 +dwReflectiveLoaderOffset  入口点偏移
 
            lpReflectiveLoader = (LPTHREAD_START_ROUTINE)((ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset);
 
            // create a remote thread in the host process to call the ReflectiveLoader!
            //OutputDebugString("INJECTING DLL!");
 
            //本身反射性dll 就隐蔽性高,自然不可以用createremoteprocess
 
            RtlCreateUserThread = (PRTL_CREATE_USER_THREAD)(GetProcAddress(GetModuleHandle(TEXT