首页
论坛
课程
招聘
[原创]远程注入之dll模块深度隐藏
2018-6-21 16:44 20733

[原创]远程注入之dll模块深度隐藏

2018-6-21 16:44
20733

远程注入的弊端

目录

我们知道,通过CreateRemoteThread,传递LoadLibrary作为线程地址,写入对方空间的dll路径作为线程参数,那么就可以把dll注入到对方的空间中.但是这有个问题,对方很容易就可以发现我们注入的dll模块.

 

还有一种方法就是通过写入ShellCode进入对目标空间,然后在用CreateRemoteThread启动,但是写ShellCode很麻烦,每一个API函数的地址都需要自己获取,而且不能像直接写高级语言一样写ShellCode.

 

那么有没有一种方法,既可以让对方看不到自己的模块,也不需要自己定位API那,就像平常时写高级语言一样简单那.

 

答案肯定是有的,请看图:

 

解决远程注入的弊端

1. 新建一个Dll文件

2.申请内存空间

DWORD HideModule(HMODULE hModule)
{
    PIMAGE_DOS_HEADER  pDos = (PIMAGE_DOS_HEADER)hModule;//DOS 头
    PIMAGE_NT_HEADERS  pNt = (PIMAGE_NT_HEADERS)((DWORD)hModule + pDos->e_lfanew);//NT 头

    //1.申请空间  从扩展头获取dll加载进入内存的大小OptionalHeader.SizeOfImage
    PBYTE mem = (PBYTE)VirtualAlloc(0, pNt->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (NULL == mem)
    {
            //申请空间失败,做些啥.....
        return NULL;
    }
    ........
}

3.拷贝dll进入内存空间

//2.拷贝到新的空间
    memcpy(mem, (void *)hModule, pNt->OptionalHeader.SizeOfImage);

4.修复重定位

//3.修复重定位   数据目录第6项是重定位表
    PIMAGE_BASE_RELOCATION  rBase = (PIMAGE_BASE_RELOCATION)((DWORD)mem + pNt->OptionalHeader.DataDirectory[5].VirtualAddress);
    DWORD n = 0;
    DWORD Base = (DWORD)mem;
    DWORD offset = (DWORD)mem - (DWORD)hModule;//
    if (offset == 0)
        (DWORD)mem;

    typedef struct RELOCATIONITEM
    {
        WORD value : 12;
        WORD attr : 4;

    } *PRELOCATIONITEM;
    PRELOCATIONITEM   rItem;
    DWORD *item;
    while (true)
    {
        if (rBase->SizeOfBlock == 0)
            break;
        rItem = (PRELOCATIONITEM)((PBYTE)rBase + 8);
        n = (rBase->SizeOfBlock - 8) / 2;
        for (int i = 0; i < n; ++i)
        {
            if (3 == rItem[i].attr)
            {
                item = (DWORD *)(Base + rBase->VirtualAddress + rItem[i].value);
                *item = (*item + offset);
            }
        }

        rBase = (PIMAGE_BASE_RELOCATION)((PBYTE)rBase + rBase->SizeOfBlock);//指向下一个结构
    }
    return (DWORD)mem;

整个dll

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
DWORD oldProtect;
BYTE  JmpBtye[5];
DWORD oldAddr;
DWORD HideModule(HMODULE hModule);
DWORD WINAPI HookMessageBox(LPVOID notUse);



BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        MessageBoxW(0, 0, 0, 0);
        DWORD newModule=HideModule(hModule);
        if (newModule)
        {

            LPTHREAD_START_ROUTINE  hook = (LPTHREAD_START_ROUTINE)(newModule + ((DWORD)HookMessageBox - (DWORD)hModule));
            hook(NULL);
            //CreateThread(0, 0, hook, 0, 0, 0);
        }
        break;
    }
    return FALSE;//返回false相当于卸载模块
}


DWORD HideModule(HMODULE hModule)
{
    PIMAGE_DOS_HEADER  pDos = (PIMAGE_DOS_HEADER)hModule;//DOS 头
    PIMAGE_NT_HEADERS  pNt = (PIMAGE_NT_HEADERS)((DWORD)hModule + pDos->e_lfanew);//NT 头

    //1.申请空间
    PBYTE mem = (PBYTE)VirtualAlloc(0, pNt->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (NULL == mem)
    {
            //申请空间失败,做些啥.....
        return NULL;
    }

    //2.拷贝到新的空间
    memcpy(mem, (void *)hModule, pNt->OptionalHeader.SizeOfImage);


    //3.修复重定位   数据目录第6项是重定位表
    PIMAGE_BASE_RELOCATION  rBase = (PIMAGE_BASE_RELOCATION)((DWORD)mem + pNt->OptionalHeader.DataDirectory[5].VirtualAddress);
    DWORD n = 0;
    DWORD Base = (DWORD)mem;
    DWORD offset = (DWORD)mem - (DWORD)hModule;//
    if (offset == 0)
        (DWORD)mem;

    typedef struct RELOCATIONITEM
    {
        WORD value : 12;
        WORD attr : 4;

    } *PRELOCATIONITEM;
    PRELOCATIONITEM   rItem;
    DWORD *item;
    while (true)
    {
        if (rBase->SizeOfBlock == 0)
            break;
        rItem = (PRELOCATIONITEM)((PBYTE)rBase + 8);
        n = (rBase->SizeOfBlock - 8) / 2;
        for (int i = 0; i < n; ++i)
        {
            if (3 == rItem[i].attr)
            {
                item = (DWORD *)(Base + rBase->VirtualAddress + rItem[i].value);
                *item = (*item + offset);
            }
        }

        rBase = (PIMAGE_BASE_RELOCATION)((PBYTE)rBase + rBase->SizeOfBlock);//指向下一个结构
    }
    return (DWORD)mem;
}

using pMessageBoxW=int (WINAPI*)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);

pMessageBoxW ToMessageBox;

int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{
    lpText = L" 你好,路过";
    return ToMessageBox(hWnd, lpText, lpCaption, uType);
}

DWORD WINAPI HookMessageBox(LPVOID notUse)
{
    //WHERE  user32.dll

    //Find
    HMODULE hModule = LoadLibraryA("user32.dll");
    DWORD   mAddr = (DWORD)GetProcAddress(hModule, "MessageBoxW");
    ToMessageBox = (pMessageBoxW)(mAddr + 2);
    oldAddr = mAddr;
    //Hook  使用热补丁

    DWORD addr = mAddr - 5;

    VirtualProtect((void *)addr, 15, PAGE_EXECUTE_READWRITE, &oldProtect);

    JmpBtye[0] = 0xE9;
    //目标地址          指令地址
    *(DWORD *)&JmpBtye[1] = (DWORD)((long long)MyMessageBoxW - (long long)addr - 5);
    memcpy((void *)addr, JmpBtye, 5);
    //替换 mov edi,edi
    __asm
    {

        mov bx, 0xF9EB   //jmp short -5
        mov eax, mAddr
        mov [eax],bx
    }
}
void UnHook()
{
    __asm
    {
        mov bx, 0xFF8B
        mov eax, oldAddr
        mov[eax], bx
    }
}

注入部分的代码:

#include <windows.h>


//获取进程句柄
HANDLE GetThePidOfTargetProcess(HWND hwnd)
{
    DWORD pid;
    GetWindowThreadProcessId(hwnd, &pid);
    HANDLE hProcee = ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_CREATE_THREAD, 0, pid);
    return hProcee;
}
//提升权限
void Up()
{
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tp;
    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    tp.Privileges[0].Luid = luid;
    AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}

//进程注入

BOOL DoInjection(char *DllPath, HANDLE hProcess)
{
    DWORD BufSize = strlen(DllPath)+1;
    LPVOID AllocAddr = VirtualAllocEx(hProcess, NULL, BufSize, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, AllocAddr, DllPath, BufSize, NULL);
    PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");

    HANDLE hRemoteThread;
    hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, pfnStartAddr, AllocAddr, 0, NULL);
    if (hRemoteThread)
    {
        MessageBox(NULL, TEXT("注入成功"), TEXT("提示"), MB_OK);
        return true;
    }
    else
    {
        MessageBox(NULL, TEXT("注入失败"), TEXT("提示"), MB_OK);
        return false;
    }
}


int main()
{
    //这里填写窗口标题
    HWND hwnd=FindWindowExA(NULL, NULL, NULL, "TestMFC");
    Up();
    HANDLE hP = GetThePidOfTargetProcess(hwnd);
    //开始注入
    //这里填写Dll路径
    DoInjection("E:\\studio\\VS2017\\HideDll\\Debug\\HideDll.dll", hP);
}
#include <windows.h>


//获取进程句柄
HANDLE GetThePidOfTargetProcess(HWND hwnd)
{
    DWORD pid;
    GetWindowThreadProcessId(hwnd, &pid);
    HANDLE hProcee = ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_CREATE_THREAD, 0, pid);
    return hProcee;
}
//提升权限
void Up()
{
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tp;
    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    tp.Privileges[0].Luid = luid;
    AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}

//进程注入

BOOL DoInjection(char *DllPath, HANDLE hProcess)
{
    DWORD BufSize = strlen(DllPath)+1;
    LPVOID AllocAddr = VirtualAllocEx(hProcess, NULL, BufSize, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, AllocAddr, DllPath, BufSize, NULL);
    PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");

    HANDLE hRemoteThread;
    hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, pfnStartAddr, AllocAddr, 0, NULL);
    if (hRemoteThread)
    {
        MessageBox(NULL, TEXT("注入成功"), TEXT("提示"), MB_OK);
        return true;
    }
    else
    {
        MessageBox(NULL, TEXT("注入失败"), TEXT("提示"), MB_OK);
        return false;
    }
}


int main()
{
    //这里填写窗口标题
    HWND hwnd=FindWindowExA(NULL, NULL, NULL, "TestMFC");
    Up();
    HANDLE hP = GetThePidOfTargetProcess(hwnd);
    //开始注入
    //这里填写Dll路径
    DoInjection("E:\\studio\\VS2017\\HideDll\\Debug\\HideDll.dll", hP);
}

查看效果:

没注入前:

 

 

 

注入之后

 

 

 

可以看到并没有看到注入的模块.


第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞1
打赏
分享
打赏 + 2.00
打赏次数 1 金额 + 2.00
 
赞赏  junkboy   +2.00 2018/06/21
最新回复 (46)
雪    币: 95
活跃值: 活跃值 (60)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pccq 活跃值 2018-6-21 17:04
2
0
感谢分享
雪    币: 201
活跃值: 活跃值 (681)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yy虫子yy 活跃值 2018-6-21 17:05
3
0
也可以不修复重定位,在卸载的地址revirtual
雪    币: 49
活跃值: 活跃值 (168)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
化魔 活跃值 2018-6-21 19:53
4
0
我想知道全局HOOK,怎么隐藏DLL文件,      SetWindowsHookEx
雪    币: 2200
活跃值: 活跃值 (179)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
youxiaxy 活跃值 2018-6-21 20:51
5
0
学习了。
雪    币: 1520
活跃值: 活跃值 (396)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chinarenjf 活跃值 2018-6-21 21:39
6
0
加壳的DLL不可以吧.
雪    币: 6817
活跃值: 活跃值 (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
聖blue 活跃值 2018-6-21 22:51
7
0
雪    币: 277
活跃值: 活跃值 (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mimotion 活跃值 2018-6-22 00:19
8
0
mark  学习了
雪    币: 2098
活跃值: 活跃值 (776)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
chpeagle 活跃值 2018-6-22 00:20
9
0
chinarenjf 加壳的DLL不可以吧.
可以的
雪    币: 2098
活跃值: 活跃值 (776)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
chpeagle 活跃值 2018-6-22 00:21
10
0
化魔 我想知道全局HOOK,怎么隐藏DLL文件, SetWindowsHookEx
这个也是一样的,代码都不用修改
雪    币: 159
活跃值: 活跃值 (708)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
fengyunabc 活跃值 1 2018-6-22 01:08
11
0
感谢分享
雪    币: 93
活跃值: 活跃值 (38)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
isdebug 活跃值 2018-6-22 06:15
12
0
最多算是分享吧? 
雪    币: 178
活跃值: 活跃值 (169)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wujimaa 活跃值 1 2018-6-22 09:36
13
0
内存加载dll
雪    币: 58
活跃值: 活跃值 (247)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wonderzdh 活跃值 1 2018-6-22 09:57
14
0
只是遍历不到模块罢了,遍历内存可执行属性一样暴露无遗。
雪    币: 17
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Carkem 活跃值 2018-6-22 10:25
15
0
mark 
最后于 2018-6-22 11:10 被Carkem编辑 ,原因:
雪    币: 49
活跃值: 活跃值 (168)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
化魔 活跃值 2018-6-22 10:48
16
0
chpeagle 这个也是一样的,代码都不用修改
我怎么测试直接崩溃啊,能有个例子吗。
雪    币: 2098
活跃值: 活跃值 (776)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
chpeagle 活跃值 2018-6-22 12:35
17
0
化魔 我怎么测试直接崩溃啊,能有个例子吗。
你调用SetWindowHook是在哪里调用.应该在新申请的空间里面调用,因为一开始加载进去的模块已经卸载了.
雪    币: 201
活跃值: 活跃值 (681)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yy虫子yy 活跃值 2018-6-22 14:20
18
0
化魔 我想知道全局HOOK,怎么隐藏DLL文件, SetWindowsHookEx
SetWindowsHookEx全局HOOK不建议隐藏dll
雪    币: 52
活跃值: 活跃值 (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
阮光全 活跃值 2018-6-22 17:05
19
0
楼主能上传源代码编译文件就完美了...
雪    币: 2098
活跃值: 活跃值 (776)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
chpeagle 活跃值 2018-6-22 19:38
20
0
wonderzdh 只是遍历不到模块罢了,遍历内存可执行属性一样暴露无遗。
确实,但可执行属性并不代表就是代码,但是为了防止一部分内存特征扫描可以进一步抹去PE头,导出表,导入表,重定位表,TLS表,和敏感字段.
雪    币: 287
活跃值: 活跃值 (30)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
sjh_pediy 活跃值 2018-6-23 07:17
21
0
不错的思路
雪    币: 31
活跃值: 活跃值 (228)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
靴子 活跃值 2018-6-23 07:39
22
0
GOOD~
雪    币: 1633
活跃值: 活跃值 (349)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hekes 活跃值 2018-6-24 10:06
23
0
mark
雪    币: 1
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
云霁 活跃值 2018-7-25 15:59
24
0
注入之后怎么卸载啊
雪    币: 2098
活跃值: 活跃值 (776)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
chpeagle 活跃值 2018-7-26 15:41
25
0
云霁 注入之后怎么卸载啊
还原Hook,释放内存就卸载了.但是不能直接在模块里调用VirtualFree(这样做的后果很可能就是直接崩溃),应该在栈里面构造一段代码来执行VirtualFree.或者在不属于释放模块的内存空间.如果要在模块里调用VirutalFree,应该在堆栈构造参数,堆栈内容为:[返回EIP,VirtualFree的参数],然后jmp VirtualFree.返回EIP就是主程序进入模块前下一条指令的地址.
游客
登录 | 注册 方可回帖
返回