吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6705|回复: 29
收起左侧

[C&C++ 原创] 【VC】内存注入

  [复制链接]
舒默哦 发表于 2020-5-19 23:13
本帖最后由 舒默哦 于 2020-5-23 22:52 编辑



内存注入的步骤
1、以二进制的方式把dll读到内存
2、拉伸dll
3、在要注入的目标进程申请内存
4、修复重定位和IAT表
5、得到dll在目标进程的入口
6、构造shellcode
7、创建远程线程

注:构造shellcode的目的是为了传参,因为CreateRemoteThread这个函数传参用的是一个地址,而dll的入口要传三个参数,所以只能构造shellcode来跳转





实验用的test_dll.dll只有一个MessageBox(NULL, "注入成功", "恭喜", MB_OK);
要注入的程序是ipmsg.exe,其他程序也一样,只要该程序的IAT表有MessageBoxA就可以,不然,注入成功了信息框不能弹出
编译用的是vs2017  字集是多字符集

test_dll.dll
[C] 纯文本查看 复制代码
BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        
        MessageBox(NULL, "注入成功", "恭喜", MB_OK);

    }
    case DLL_THREAD_ATTACH:
        //MessageBox(NULL, "DLL_THREAD_ATTACH", "", MB_OK);
    case DLL_THREAD_DETACH:
        //MessageBox(NULL, "DLL_THREAD_DETACH", "", MB_OK);
    case DLL_PROCESS_DETACH:
        //MessageBox(NULL, "DLL_PROCESS_DETACH", "", MB_OK);
        break;
    }
    return TRUE;
}


main.cpp
[C++] 纯文本查看 复制代码
#include <iostream>
#include <Windows.h>
#include "resource.h"

#define path_dll "C:\\Users\\daddy\\Desktop\\软件代码区\\dll库\\test_dll\\Release\\test_dll.dll"
#define GET_HEADER_DICTIONARY(module, idx)        &(module)->headers->OptionalHeader.DataDirectory[idx]

#ifdef _WIN64
#define POINTER_TYPE ULONGLONG
#else
#define POINTER_TYPE DWORD
#endif

//获取文件的在内存的地址和大小
int GetBuffAddrAndSizeofFile(char* FilePath, _Out_  DWORD* buff, _Out_ DWORD* FileSize, _Out_ DWORD* FileSize1);

//修复重定位表
void PerformBaseRelocation(char* buff, DWORD Value);

//重建IAT表
BOOL RebuildImportTable(char* buff);

//拉伸文件
DWORD StretchFile(DWORD pFileBuff, DWORD FileSize);


//内存注入
void MemoryInject(DWORD dwPID)
{
    //1.把dll文件加载到内存
    DWORD pFileBuf_dll = 0;//dll在内存中的地址
    DWORD FileSize_dll = 0;//dll的内存大小
    DWORD FileSize_dll_1 = 0;//dll的文件大小
    if (GetBuffAddrAndSizeofFile((char*)path_dll, &pFileBuf_dll, &FileSize_dll, &FileSize_dll_1) == 0)
    {
        return;
    }

    //2.拉伸dll
    DWORD NewBuff = StretchFile(pFileBuf_dll, FileSize_dll);

    //释放pFileBuf_dll
    delete[](char*)pFileBuf_dll;
    //获取PE头和NT头
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)NewBuff;
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)NewBuff + pDosHeader->e_lfanew);

    //3.0打开目标进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, dwPID);

    //3.1在目标进程申请内存
    LPBYTE lpbPeAddress = (LPBYTE)VirtualAllocEx(hProcess, NULL, FileSize_dll, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (NULL == lpbPeAddress)
    {
        printf("在目标进程申请内存失败!");
        return;
    }

    //4.0 修复重定位表
    DWORD locationDelta = (SIZE_T)((DWORD)lpbPeAddress - pNtHeader->OptionalHeader.ImageBase);
    if (0 != locationDelta)
    {
        PerformBaseRelocation((char*)NewBuff, locationDelta);
    }

    //4.1 修复IAT表
    if (!RebuildImportTable((char*)NewBuff))
    {
        printf("修复失败!");
        return;
    }

    //把修复后的dll数据拷贝到目标进程内存
    BOOL res = WriteProcessMemory(hProcess, lpbPeAddress, (LPCVOID)NewBuff, FileSize_dll, 0);
    if (0 == res)
    {
        printf("在目标进程写入失败!");
        VirtualFreeEx(hProcess, lpbPeAddress, FileSize_dll, MEM_RELEASE);
        CloseHandle(hProcess);
        return;
    }

    //5.找到dll在目标进程的入口
    DWORD EnterPointer = (DWORD)lpbPeAddress + pNtHeader->OptionalHeader.AddressOfEntryPoint;

    //dll入口参数结构体
    typedef struct MyStruct
    {        
        HMODULE hModule;                
        DWORD  ul_reason_for_call;
        LPVOID lpReserved;
    }ParamCall; 

    ParamCall paramcall;
    paramcall.hModule = (HMODULE)lpbPeAddress;//DLL模块在进程虚拟空间中的起始地址
    paramcall.ul_reason_for_call = DLL_PROCESS_ATTACH;
    paramcall.lpReserved = 0;
    

    //在目标进程申请内存
    LPBYTE shlcodeaddr = (LPBYTE)VirtualAllocEx(hProcess, NULL, 0x40, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    //E8 XXXXXXXX = 要跳转的地址 - E8指令所在的地址 - 5
    DWORD jmp_addr = EnterPointer - ((DWORD)shlcodeaddr + 15) - 5;

    //6.构造shellcode
    char shellcode[] = {
        0x68,
        ((DWORD)paramcall.lpReserved)&0xFF, (((DWORD)paramcall.lpReserved) & 0xFF00) >> 8,(((DWORD)paramcall.lpReserved) & 0xFF0000) >> 16,((DWORD)paramcall.lpReserved) >> 24,
        0x68,
        (paramcall.ul_reason_for_call) & 0xFF, ((paramcall.ul_reason_for_call) & 0xFF00) >> 8,((paramcall.ul_reason_for_call) & 0xFF0000) >> 16,(paramcall.ul_reason_for_call) >> 24,
        //0x6A,0x0,0x6A,0x1,
        0x68,
        ((DWORD)paramcall.hModule) & 0xFF, (((DWORD)paramcall.hModule) & 0xFF00) >> 8,(((DWORD)paramcall.hModule) & 0xFF0000) >> 16,((DWORD)paramcall.hModule) >> 24,        
        0xE8,
        (jmp_addr) & 0xFF, ((jmp_addr) & 0xFF00) >> 8,((jmp_addr) & 0xFF0000) >> 16,(jmp_addr) >> 24,
        0xC3
        
    };

    if (!WriteProcessMemory(hProcess, shlcodeaddr, (LPCVOID)shellcode, sizeof(shellcode), NULL))
    {
        MessageBox(NULL,"Write trueAddress failed","",MB_OK);
        return;
    }

    //7.开启远程线程
    DWORD threadId;
    HANDLE hThead;
    hThead = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)shlcodeaddr, 0, 0, &threadId);
    WaitForSingleObject(hThead, -1);
    CloseHandle(hThead);

    //释放NewBuff
    delete[](char*)NewBuff;
}

int main()
{
    DWORD pid=0;
    printf("请输入进程ID: ");
    scanf_s("%d", &pid);
    MemoryInject(pid);
    std::cout << "Hello World!\n"; 
}

//修复重定位表
void PerformBaseRelocation(char* buff, DWORD Value)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)buff;
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(buff + pDosHeader->e_lfanew);

    //获取目录表头指针
    PIMAGE_DATA_DIRECTORY pDataDirectory = pNtHeader->OptionalHeader.DataDirectory;
    if (pDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
    {
        PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION)((DWORD)buff + pDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
        while (relocation->VirtualAddress > 0)
        {
            BYTE* dest = (PBYTE)((DWORD)buff + relocation->VirtualAddress);
            WORD* relInfo = (PWORD)((DWORD)relocation + sizeof(IMAGE_BASE_RELOCATION));
            for (int i = 0; i < ((relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2); ++i, ++relInfo)
            {
                DWORD *patchAddrHL;
                int type, offset;

                //the upper 4 bits define the type of relocation
                type = *relInfo >> 12;
                //the lower 12 bits define the offset
                offset = *relInfo & 0xFFF;

                switch (type)
                {
                case IMAGE_REL_BASED_ABSOLUTE:
                    //skip relocation
                    break;
                case IMAGE_REL_BASED_HIGHLOW:
                    //change comlete 32 bit address
                    patchAddrHL = (PDWORD)(dest + offset);
                    *patchAddrHL += Value;
                    break;
                default:
                    break;
                }
            }

            //advance to next relocation block
            relocation = PIMAGE_BASE_RELOCATION((DWORD)relocation + relocation->SizeOfBlock);
        }
    }

}

//重建IAT表
BOOL RebuildImportTable(char* buff)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)buff;
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(buff + pDosHeader->e_lfanew);
    int result = 1;
    //获取目录表头指针
    PIMAGE_DATA_DIRECTORY pDataDirectory = pNtHeader->OptionalHeader.DataDirectory;

    if (pDataDirectory[1].Size > 0)
    {
        //获取导入表地址
        PIMAGE_IMPORT_DESCRIPTOR ImportAddr = PIMAGE_IMPORT_DESCRIPTOR(pDataDirectory[1].VirtualAddress + (DWORD)buff);

        for (; !IsBadReadPtr(ImportAddr, sizeof(PIMAGE_IMPORT_DESCRIPTOR)) && ImportAddr->Name; ++ImportAddr)
        {
            POINTER_TYPE *thunkRef;
            FARPROC *funcRef;

            HMODULE hModule = LoadLibrary((LPCSTR)(buff + ImportAddr->Name));

            if (ImportAddr->OriginalFirstThunk)
            {
                thunkRef = (POINTER_TYPE *)(buff + ImportAddr->OriginalFirstThunk);
                funcRef = (FARPROC*)(buff + ImportAddr->FirstThunk);
            }
            else
            {
                //no hint table
                thunkRef = (POINTER_TYPE *)(buff + ImportAddr->FirstThunk);
                funcRef = (FARPROC*)(buff + ImportAddr->FirstThunk);
            }

            for (; *thunkRef; ++thunkRef, ++funcRef)
            {
                if (IMAGE_SNAP_BY_ORDINAL(*thunkRef))
                {
                    *funcRef = GetProcAddress(hModule, (LPCSTR)IMAGE_ORDINAL(*thunkRef));
                }
                else
                {
                    PIMAGE_IMPORT_BY_NAME pFuncName = (PIMAGE_IMPORT_BY_NAME)(*thunkRef + (DWORD)buff);
                    *funcRef = GetProcAddress(hModule, (LPCSTR)&pFuncName->Name);
                }
                if (*funcRef == 0)
                {
                    result = 0;
                    break;
                }
            }
        }
    }
    return result;
}

//获取文件的在内存的地址和大小
int GetBuffAddrAndSizeofFile(char* FilePath, _Out_ DWORD* buff, _Out_ DWORD* FileSize, _Out_ DWORD* FileSize1)
{
    //1.1 获取文件句柄
    HANDLE hFile = CreateFile(
        FilePath,
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    //1.2 获取文件大小
    DWORD dwFileSize = GetFileSize(hFile, NULL);
    CHAR *pFileBuf = new CHAR[dwFileSize];
    memset(pFileBuf, 0, dwFileSize);

    //1.3 将文件读取到内存
    DWORD ReadSize = 0;
    ReadFile(hFile, pFileBuf, dwFileSize, &ReadSize, NULL);

    //1.4 关闭句柄
    CloseHandle(hFile);


    //2.1 判断是否为PE文件
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuf;
    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        printf("不是MZ开头\n");
        return 0;
    }
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pFileBuf + pDosHeader->e_lfanew);
    if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
    {
        printf("不是PE文件\n");
        return 0;
    }

    //2.2 把文件的在内存中的地址和大小分别赋值给参数二和参数三
    *buff = (DWORD)pFileBuf;
    *FileSize = pNtHeader->OptionalHeader.SizeOfImage;
    *FileSize1 = dwFileSize;
    return 1;
}

//拉伸文件
DWORD StretchFile(DWORD pFileBuff, DWORD FileSize)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuff;
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pFileBuff + pDosHeader->e_lfanew);

    //1.1 根据内存大小 申请内存
    char* NewFileBuff = new char[FileSize];
    if (NewFileBuff == NULL)
    {
        printf("内存申请失败!");
        return 0;
    }
    memset(NewFileBuff, 0, FileSize);

    //1.2 拉伸文件
     // 拷贝DOS头 + DOS STUB + PE头到headers地址处
    memcpy(NewFileBuff, pDosHeader, pNtHeader->OptionalHeader.SizeOfHeaders);

    // 从dll文件内容中拷贝每个section(节)的数据到新的内存区域
    PIMAGE_OPTIONAL_HEADER32 OptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileBuff + pDosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);
    PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)OptionalHeader + pNtHeader->FileHeader.SizeOfOptionalHeader);

    for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++, pSectionHeader++)
    {
        char* x = (char*)NewFileBuff + pSectionHeader->VirtualAddress;
        char* y = (char*)pFileBuff + pSectionHeader->PointerToRawData;
        memcpy(x, y, pSectionHeader->SizeOfRawData);
    }

    return (DWORD)NewFileBuff;
}



clipboard.png
clipboard1.png

ipmsg.7z

64.48 KB, 下载次数: 231, 下载积分: 吾爱币 -1 CB

ipmsg.exe

免费评分

参与人数 9吾爱币 +12 热心值 +9 收起 理由
非洲小白脸. + 1 + 1 貌似IAT修复不能在自己进程进行,好像是因为自进程和目标进程获取的函数地址.
hj170520 + 1 + 1 评分冷却时间结束,就跑过来给大哥评分了
wushaominkk + 5 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
azw80 + 1 + 1 有一年听说DNF用搜狗注入
lou7878 + 1 + 1 热心回复!
qoovoop + 1 + 1 谢谢@Thanks!
朱朱你堕落了 + 1 看不懂,我只是来看热闹的。
xiaomo1249 + 1 + 1 未接触过编程 感觉太难 刚开始 需要学哪个呢
boy7928 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

XuanCi 发表于 2020-11-25 10:40
舒默哦 发表于 2020-11-24 22:55
可能游戏有检测,用OD跟一下

不是哦  自己写的程序 内存注入都卡死然后闪退 不知道什么问题
hj170520 发表于 2020-5-19 23:19
JavaSB 发表于 2020-5-19 23:22
xiaomo1249 发表于 2020-5-20 00:09
不懂 太难了
hj170520 发表于 2020-5-20 00:13
舒默哦 发表于 2020-5-19 23:30
我服了,东西都到嘴边了还不会,手把手我过段时间再写详细点吧

原谅我是个菜鸡。刚刚在把我另一个求助帖子看了看,我自己解决了我自己的问题。
azw80 发表于 2020-5-20 08:55
希望有个手把手教程,哈哈,热心和评分都给楼主了~
xlhwxyh 发表于 2020-5-20 08:47
最后在抹掉 PE头, 然后暴力搜索内存也不行了!
还可以用在反破解,    OD载入进去,你也会发现无法保存文件,对于新手,那就是无解!!!!!!!!!!!!!!!
 楼主| 舒默哦 发表于 2020-5-19 23:23
hj170520 发表于 2020-5-19 23:19
. 感觉可以用作外挂~

给我投币老铁,明天更新文件永久注入
hj170520 发表于 2020-5-19 23:28
舒默哦 发表于 2020-5-19 23:23
给我投币老铁,明天更新文件永久注入

老哥,今天我币投了~明天吧!
我也不会用这玩意~,有没有手把手教的教程
 楼主| 舒默哦 发表于 2020-5-19 23:30
hj170520 发表于 2020-5-19 23:28
老哥,今天我币投了~明天吧!
我也不会用这玩意~,有没有手把手教的教程

我服了,东西都到嘴边了还不会,手把手我过段时间再写详细点吧
MC阿虎 发表于 2020-5-19 23:50
学到了,来打卡
boy7928 发表于 2020-5-20 00:02
shellcode应该如何写呢 看不太懂
 楼主| 舒默哦 发表于 2020-5-20 00:03
boy7928 发表于 2020-5-20 00:02
shellcode应该如何写呢 看不太懂

push xxxxx
push xxxxx
push xxxxx
call   xxxxx
ret
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 16:22

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表