舒默哦 发表于 2020-5-19 23:13

【VC】内存注入

本帖最后由 舒默哦 于 2020-5-23 22:52 编辑

https://static.52pojie.cn/static/image/hrline/4.gif

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

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



https://static.52pojie.cn/static/image/hrline/1.gif

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

test_dll.dll
BOOL APIENTRY DllMain(HMODULE hModule,
    DWORDul_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
#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

#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;               
      DWORDul_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.Size > 0)
    {
      PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION)((DWORD)buff + pDataDirectory.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.Size > 0)
    {
      //获取导入表地址
      PIMAGE_IMPORT_DESCRIPTOR ImportAddr = PIMAGE_IMPORT_DESCRIPTOR(pDataDirectory.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;
    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;
    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;
}


XuanCi 发表于 2020-11-25 10:40

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

不是哦自己写的程序 内存注入都卡死然后闪退 不知道什么问题

hj170520 发表于 2020-5-19 23:19

{:301_1001:}. 感觉可以用作外挂~

JavaSB 发表于 2020-5-19 23:22

好东西,谢谢分享

xiaomo1249 发表于 2020-5-20 00:09

不懂 太难了{:1_909:}

hj170520 发表于 2020-5-20 00:13

舒默哦 发表于 2020-5-19 23:30
我服了,东西都到嘴边了还不会,手把手我过段时间再写详细点吧

{:301_971:}原谅我是个菜鸡。刚刚在把我另一个求助帖子看了看,我自己解决了我自己的问题。{:301_998:}

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
. 感觉可以用作外挂~

给我投币老铁,:$qqq明天更新文件永久注入

hj170520 发表于 2020-5-19 23:28

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

{:301_999:} 老哥,今天我币投了~明天吧!
我也不会用这玩意~,有没有手把手教的教程{:301_998:}

舒默哦 发表于 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
页: [1] 2 3
查看完整版本: 【VC】内存注入