yoyoRev 发表于 2022-11-18 16:46

c/c++实现内存注入

本帖最后由 yoyoRev 于 2022-11-18 23:45 编辑

看了相关视频,是易语言实现的内存注入,用c/c++来实现一下

内存注入的基本步骤:
1.将要注入的dll文件读取到缓冲区然后拉伸
2.对拉伸后的dll文件进行重定位表的修复
3.起远程线程修复iat表
4.抹除pe指纹,跳转到oep

以下是dll文件代码,只有一个MessageBox函数

```
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                     DWORDul_reason_for_call,
                     LPVOID lpReserved
                     )
{
   
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
      MessageBox(0, TEXT("测试dll"), 0, 0);
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
      break;
    }
    return TRUE;
}
```


以下是注入器代码

```
#include <stdio.h>
#include <windows.h>
typedef struct _InjcetPara {
      DWORD NewImageBase;
      DWORD AddressOfEntryPoint;
      LPVOID LoadLibraryAdd;
      LPVOID GetProcAdd;
      DWORD RvaIdt;
      DWORD SizeOfHeaders;
}InjcetPara,*PInjcetPara;
InjcetPara inp;

BYTE ReIat[] = "\x8B\xFF\x55\x8B\xEC\x83\xEC\x40\x8B\x45\x08\x36\x8B\
\x18\x89\x5D\xFC\x36\x8B\x58\x08\x89\x5D\xF8\x36\x8B\x58\x0C\x89\x5D\xF4\
\x8B\x50\x10\x03\x55\xFC\x89\x55\xEC\x8B\x55\xEC\x83\x7A\x0C\x00\x74\x68\x8B\
\x42\x0C\x03\x45\xFC\x50\xFF\x55\xF8\x89\x45\xE8\xC7\x45\xF0\x00\x00\x00\x00\
\x8B\x55\xEC\x8B\x42\x10\x03\x45\xFC\x89\x45\xE4\x8B\x45\xE4\x8B\xD8\x8B\x7D\xF0\
\xC1\xE7\x02\x83\x3C\x1F\x00\x74\x31\x8B\x04\x1F\xA9\x00\x00\x00\x80\x74\x09\x25\
\xFF\xFF\xFF\x7F\x8B\xD0\xEB\x06\x03\x45\xFC\x8D\x50\x02\x52\xFF\x75\xE8\xFF\x55\xF4\
\x8B\x5D\xE4\x8B\x75\xF0\xC1\xE6\x02\x89\x04\x1E\xFF\x45\xF0\xEB\xBE\x83\x45\xEC\x14\
\xEB\x8F\xFC\x8B\x7D\xFC\x33\xC0\x8B\x5D\x08\x36\x8B\x4B\x14\xC1\xE9\x02\xF3\xAB\x6A\x00\
\x6A\x00\x6A\x01\xFF\x75\xFC\x36\x8B\x43\x04\x03\x45\xFC\xFF\xD0\xC9\xC3";
BOOL FileToImage(PDWORD pFile,PDWORD pImage,PDWORD pImageSize) {
      DWORD ImageBufferSize = 0;
      PIMAGE_DOS_HEADER pNt = (PIMAGE_DOS_HEADER)pFile;
      PIMAGE_FILE_HEADER pFileHead = PIMAGE_FILE_HEADER((DWORD)pFile + pNt->e_lfanew + 4);
      PIMAGE_OPTIONAL_HEADER pOption = PIMAGE_OPTIONAL_HEADER(pFileHead + 1);
      PIMAGE_SECTION_HEADER pSection = PIMAGE_SECTION_HEADER((DWORD)pFileHead +0x14 + pFileHead->SizeOfOptionalHeader);
      inp.AddressOfEntryPoint = pOption->AddressOfEntryPoint;
      inp.SizeOfHeaders = pOption->SizeOfHeaders;
      ImageBufferSize = pOption->SizeOfImage;
      *pImageSize = pOption->SizeOfImage;
      PBYTE pImageFile = (PBYTE)malloc(ImageBufferSize);
      if (!pImageFile) {
                return 0;
      }
      *pImage = (DWORD)pImageFile;
      memset(pImageFile,0, ImageBufferSize);
      memcpy((PBYTE)pImageFile, (PBYTE)pFile, pOption->SizeOfHeaders);
      //printf("%s\n", pSection->Name);
      for (int i = 0; i < pFileHead->NumberOfSections; i++) {
                memcpy(PBYTE((DWORD)pImageFile+ pSection->VirtualAddress), PBYTE((DWORD)pFile+ pSection->PointerToRawData), pSection->SizeOfRawData);
                pSection++;
      }
      return 0;
}

BOOL Reloc(PDWORD pImage,DWORD NewImageBase) {
      PIMAGE_DOS_HEADER pNt = (PIMAGE_DOS_HEADER)pImage;
      PIMAGE_FILE_HEADER pFileHead = PIMAGE_FILE_HEADER((DWORD)pImage + pNt->e_lfanew + 4);
      PIMAGE_OPTIONAL_HEADER pOption = PIMAGE_OPTIONAL_HEADER(pFileHead + 1);
      PIMAGE_DATA_DIRECTORY pDataDire = PIMAGE_DATA_DIRECTORY((DWORD)(pFileHead + 1) + 0x60);
      if (!(pDataDire + 5)->VirtualAddress) {
                printf("没有重定位表\n");
                return 0;
      }
      inp.RvaIdt = (pDataDire + 1)->VirtualAddress;
      PIMAGE_BASE_RELOCATION pbreloc = PIMAGE_BASE_RELOCATION((DWORD)pImage + (pDataDire + 5)->VirtualAddress);
      PWORD PReFlag = 0;
      while (pbreloc->VirtualAddress) {
                PReFlag = PWORD(pbreloc + 1);
                for (int i = 0; i < (pbreloc->SizeOfBlock - 8) / 2; i++) {
                        if ((*PReFlag & 0xf000) == 0x3000) {
                              PDWORD ptemp = PDWORD(pbreloc->VirtualAddress + (*PReFlag & 0xfff) + (DWORD)pImage);
                              *ptemp = *ptemp - pOption->ImageBase + NewImageBase;
                        }
                        PReFlag++;
                }
                pbreloc = PIMAGE_BASE_RELOCATION((DWORD)pbreloc + pbreloc->SizeOfBlock);
      }
      return 1;
}
DWORD CreateMapFile(LPCSTR lpFileName, PDWORD pFileSize) {
      HANDLE hFile = INVALID_HANDLE_VALUE;
      HANDLE hMapFile = INVALID_HANDLE_VALUE;
      DWORD FileSize = NULL;
      LPVOID lpMemory = NULL;
      //读取文件
      hFile = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
      if (!hFile) {
                MessageBox(0, TEXT("读取文件失败"), 0, 0);
                return 0;
      }
      //获取文件大小
      FileSize = GetFileSize(hFile, NULL);
      if (!FileSize) {
                MessageBox(0, TEXT("获取文件大小失败"), 0, 0);
                return 0;
      }
      *pFileSize = FileSize;
      //创建文件映像
      hMapFile = CreateFileMappingA(hFile, NULL, PAGE_READWRITE, 0, FileSize, NULL);
      if (!hMapFile) {
                MessageBox(0, TEXT("创建文件映像失败"), 0, 0);
                return 0;
      }
      lpMemory = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
      if (!lpMemory) {
                MessageBox(0, TEXT("调用文件映射失败"), 0, 0);
                return 0;
      }
      CloseHandle(hFile);
      CloseHandle(hMapFile);
      return (DWORD)lpMemory;
}
HANDLE GetProcessHandle(DWORD dwProcessId) {
      HANDLE hProcess = NULL;
      hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
      if (!hProcess) {
                printf("打开进程句柄失败,错误码:%d\n",GetLastError());
      }
      return hProcess;
}
int main(int argc, char* argv[]) {
      
      DWORD ImageAddress = 0;
      DWORD ImageSize = 0;
      DWORD FileSize = 0;
      DWORD ThreadReIat = 0;
      if (argc < 3) {
                printf("参数不够,注入失败\n");
                return 0;
      }
      DWORD dwProcessId = atoi(argv);
      HANDLE hProcess = GetProcessHandle(dwProcessId);
      if (!hProcess) {
                return 0;
      }
      DWORD MeMoryAddress = CreateMapFile(argv, &FileSize);
      if (!MeMoryAddress) {
                return 0;
      }
      FileToImage((PDWORD)MeMoryAddress,&ImageAddress,&ImageSize);
      UnmapViewOfFile((LPVOID)MeMoryAddress);
      DWORD NewImageBase = (DWORD)VirtualAllocEx(hProcess,NULL, ImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
      if (!NewImageBase) {
                printf("申请空间失败\n");
                return 0;
      }
      inp.NewImageBase = NewImageBase;
      if (!Reloc((PDWORD)ImageAddress, NewImageBase)) {
                printf("模块没有重定位表,注入失败\n");
                VirtualFreeEx(hProcess, (LPVOID)NewImageBase, 0, MEM_RELEASE);
                return 0;
      }
      HMODULE hKernel = LoadLibraryA("kernel32.dll");
      if (!hKernel) {
                printf("获取kernel32句柄失败\n");
                VirtualFreeEx(hProcess, (LPVOID)NewImageBase, 0, MEM_RELEASE);
                return 0;
      }
      inp.LoadLibraryAdd = GetProcAddress(hKernel,"LoadLibraryA");
      inp.GetProcAdd = GetProcAddress(hKernel, "GetProcAddress");
      if (!inp.LoadLibraryAdd || !inp.GetProcAdd) {
                printf("获取函数地址失败\n");
                VirtualFreeEx(hProcess, (LPVOID)NewImageBase, 0, MEM_RELEASE);
                return 0;
      }
      WriteProcessMemory(hProcess, (LPVOID)NewImageBase, (LPCVOID)ImageAddress,ImageSize, NULL);
      ThreadReIat = (DWORD)VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
      if (!ThreadReIat) {
                printf("申请线程空间失败\n");
                return 0;
      }
      WriteProcessMemory(hProcess, (LPVOID)ThreadReIat,&inp,sizeof(inp),NULL);
      WriteProcessMemory(hProcess, (LPVOID)(ThreadReIat +0x30), &ReIat, sizeof(ReIat), NULL);
      //远程线程修复iat表
      HANDLE hReIat = CreateRemoteThread(hProcess,NULL,NULL, LPTHREAD_START_ROUTINE(ThreadReIat + 0x30),(LPVOID)ThreadReIat,0,NULL);
      if (!hReIat) {
                printf("创建远程线程失败,修复IAT表失败\n");
                return 0;
      }
      WaitForSingleObject(hReIat,INFINITE);
      
      VirtualFreeEx(hProcess, (LPVOID)NewImageBase, 0, MEM_RELEASE);
      VirtualFreeEx(hProcess, (LPVOID)ThreadReIat, 0, MEM_RELEASE);
      
      return 0;
}
```

构造了一个结构体,用于远程线程修复iat表,BYTE ReIat[]是进行修复IAT表的shellcode

具体汇编代码如下

```
;参数说明
      ;ebp-4:dll文件基址
      ;ebp-8:LoadLibrary函数地址
      ;ebp-c:GetProcAddress函数地址
      ;ebp-10:IAT数组标号
      ;ebp-14:导入表地址
      ;ebp-18:导入表NAME指向dll的基址
      ;ebp-1c:iat数组基址
      .386
    .model flat,stdcall
    option casemap:none
      
      .code
                start:
                        mov edi,edi
                        push ebp
                        mov ebp,esp
                        sub esp,40h
                        mov eax,dword ptr ss:      
                        mov ebx,dword ptr ss:      
                        mov dword ptr ss:,ebx
                        mov ebx,dword ptr ss:
                        mov dword ptr ss:,ebx
                        mov ebx,dword ptr ss:
                        mov dword ptr ss:,ebx
                        mov edx,dword ptr ds:
                        add edx,dword ptr ss:
                        mov dword ptr ss:,edx
                r2:
                        mov edx,dword ptr ss:
                        cmp dword ptr ds:,0
                        jz clPe
                        mov eax,dword ptr ds:
                        add eax,dword ptr ss:
                        push eax
                        call dword ptr ss:
                        mov dword ptr ss:,eax
                        mov dword ptr ss:,0
                        mov edx,dword ptr ss:
                        mov eax,dword ptr ds:      ;获取iat数组偏移
                        add eax,dword ptr ss:      ;指向iat数组
                        mov dword ptr ss:,eax
                IsNull:
                        mov eax,dword ptr ss:
                        mov ebx,eax
                        mov edi,dword ptr ss:
                        shl edi,2
                        cmp dword ptr ds:,0
                        jz r1
                        mov eax,dword ptr ds:
                        test eax,80000000h                        ;判断最高位是否为1
                        jz IsRva
                        and eax,7fffffffh
                        mov edx,eax
                        jmp GetProc
                IsRva:
                        add eax,dword ptr ss:
                        lea edx,dword ptr ds:
                GetProc:
                        push edx
                        push dword ptr ss:
                        call dword ptr ss:
                        mov ebx,dword ptr ss:
                        mov esi,dword ptr ss:
                        shl esi,2
                        mov dword ptr ds:,eax
                        inc dword ptr ss:
                        jmp IsNull
                r1:
                        add dword ptr ss:,14h
                        jmp r2
                clPe:                                                                ;抹除PE指纹
                        cld
                        mov edi,dword ptr ss:
                        xor eax,eax
                        mov ebx,dword ptr ss:
                        mov ecx,dword ptr ss:
                        shr ecx,2
                        rep stosd
                        push 0
                        push 1
                        push dword ptr ss:
                        mov eax,dword ptr ss:
                        add eax,dword ptr ss:
                        call eax
                        leave
                        ret
                end start
```

运行效果

unpy 发表于 2023-10-27 22:18

牛逼 {:1_921:}

请教一下:
1) BYTE ReIat[] =这段魔数代码是啥意思?怎么构造呢?
2) DLL Main中只能直接增加立即执行的逻辑,怎么去比如修改界面(比如增加菜单/按钮)当用户操作对应界面的时候才触发代码?

丶MaGuoGuo 发表于 2022-11-23 10:54

虽然看不懂 但是感觉还是挺牛逼的 楼主牛

cnv587 发表于 2022-11-27 16:16

虽然看不懂 但是感觉还是挺牛逼的 楼主牛

你猫临死前 发表于 2022-12-8 00:35

有无文件试试

紈絝 发表于 2022-12-9 21:27

有无成品啊

fuyunxiao01 发表于 2022-12-10 11:48

牛逼,我看源码还好,看非源码的代码头疼

yoyoRev 发表于 2023-1-6 19:16

你猫临死前 发表于 2022-12-8 00:35
有无文件试试

什么文件

摩托哈哈哥 发表于 2023-1-7 18:44

我一个c++菜鸟是看不太懂

ssjjtt 发表于 2023-4-24 15:52

太难了吧…………

CSGO001 发表于 2023-7-31 11:09

请问这种注入算哪一种,比如反射式,无痕什么的
页: [1] 2 3
查看完整版本: c/c++实现内存注入