专栏名称: 看雪学苑
致力于移动与安全研究的开发者社区,看雪学院(kanxue.com)官方微信公众帐号。
目录
相关文章推荐
传媒1号  ·  传媒行业,需要新思维|传媒ESG合辑 ·  2 天前  
传媒1号  ·  传媒行业,需要新思维|传媒ESG合辑 ·  2 天前  
苏州园区公安微警务  ·  守护 · 万家灯火 ·  3 天前  
苏州园区公安微警务  ·  守护 · 万家灯火 ·  3 天前  
安天集团  ·  大年初四丨安天融川给您拜年了 ·  5 天前  
51好读  ›  专栏  ›  看雪学苑

反射式注入技术浅析

看雪学苑  · 公众号  · 互联网安全  · 2025-01-21 17:59

正文

感觉反射式注入与普通注入的最大区别就是不加载系统的API去加载我们的文件,也就是不调用Loadlibrary,而是让我们手动实现装载过程,网上的文章说可以在DLL的导出表中添加ReflectiveLoader函数调用它。


由于调用它的时候,不确定DLL文件写到目标进程的哪个虚拟空间上,所以这个编写的函数必须与地址无关,这种代码叫(position-independent code)PIC,暂时理解成在DLL的导出表写入一个函数,这个函数的功能就是PELOADER。


工具

一个注射器和一个被注入的DLL


涉及知识

PEB和TEB,PEloader,dll注入(创建远程线程),函数指针,手动实现strncpy,memmove等。


X64dbg调试

我们需要x64dbg去调试查看函数的调用,内存窗口等查看值是否在里面,这里在文件—附加里面可以附加进程。



然后用vs去附加进程调试



这里可以添加监视,然后复制值到x64dbg里面,就可以实时监视我们的文件在如何被操作。


注射器

大致流程

1.将注入DLL读入自身内存

2.利用VirtualAlloc和WriteProcessMemory在目标进程中写入待注入的DLL文件

3.利用CreateRemoteThread等函数启动目标进程的ReflectiveLoader


一:遍历DLL的导出表

因为我的注射器采用的是以创建远程线程为模板,具体的代码不过多分析,就分析和普通创建远程线程不一样的调用自身函数的地方,前面所说,我们是把类似于PEloader的代码写成一个函数放在DLL文件的导出表当中。


DWORD GetReflectiveLoaderOffset(VOID* lpReflectiveDllBuffer)
{
    UINT_PTR BaseAddress = 0;//UINT_PTR是无符号指针
    UINT_PTR uiNT = 0;
    UINT_PTR uiNameArray = 0;
    UINT_PTR uiAddressArray = 0;
    UINT_PTR uiNameOrdinals = 0;
    DWORD dwCounter = 0;
#ifdef WIN_X64
    DWORD dwCompiledArch = 2;
#else
    // This will catch Win32 and WinRT.
    DWORD dwCompiledArch = 1;
#endif

    BaseAddress = (UINT_PTR)lpReflectiveDllBuffer;

    uiNT = BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew;

    //这里是主要判断当前的位数于dll位数是否一致
    if (((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.Magic == 0x010B// PE32
    {
        if (dwCompiledArch != 1)
            return 0;
    }
    else if (((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.Magic == 0x020B// PE64
    {
        if (dwCompiledArch != 2)
            return 0;
    }
    else
    {
        return 0;
    }
    //u1NameArray是PE文件导出表的条目索引
    uiNameArray = (UINT_PTR) & ((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    //uiNT是导出表的地址
    uiNT = BaseAddress + RVA(((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, BaseAddress);
   //导出表的函数名称数组
    uiNameArray = BaseAddress + RVA(((PIMAGE_EXPORT_DIRECTORY)uiNT)->AddressOfNames, BaseAddress);
   //导出表的函数地址数组
    uiAddressArray = BaseAddress + RVA(((PIMAGE_EXPORT_DIRECTORY)uiNT)->AddressOfFunctions, BaseAddress);
    //导出表的名称序号数组
    uiNameOrdinals = BaseAddress + RVA(((PIMAGE_EXPORT_DIRECTORY)uiNT)->AddressOfNameOrdinals, BaseAddress);
    dwCounter = ((PIMAGE_EXPORT_DIRECTORY)uiNT)->NumberOfNames;
    while (dwCounter--)
    {
        //这就是核心的遍历函数
        char* cpExportedFunctionName = (char*)(BaseAddress + RVA(*(DWORD*)(uiNameArray), BaseAddress));
        printf("Exported function: %s\n", cpExportedFunctionName);

        if (strstr(cpExportedFunctionName, "reflectiveinject") != NULL)
        {//strstr函数是查找,从核心函数中查找
            
            uiAddressArray = BaseAddress + RVA(((PIMAGE_EXPORT_DIRECTORY)uiNT)->AddressOfFunctions, BaseAddress);

            uiAddressArray += (*(WORD*)(uiNameOrdinals) * sizeof(DWORD));

            
            return RVA(*(DWORD*)(uiAddressArray), BaseAddress);
        }
        
        uiNameArray += sizeof(DWORD);

       
        uiNameOrdinals += sizeof(WORD);
    }

    return 0;
}


RVA函数是将虚拟地址RVA转换为文件的偏移量,这里通过遍历导出函数名称表去寻找函数,找到之后返回这个函数的地址的偏移量。


DWORD RVA(DWORD dwRva, UINT_PTR BaseAddress)
{//这个代码是将相对虚拟地址RVA转换成文件的偏移量
    WORD wIndex = 0;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    PIMAGE_NT_HEADERS pNtHeaders = NULL;

    pNtHeaders = (PIMAGE_NT_HEADERS)(BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew);

    pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader);
    //这个是找节区头,可选头加上可选头的大小,下一个就是节区表头
    //就是查找给的RVA是属于哪个节区,其目的就是找到文件偏移地址
    if (dwRva 0].PointerToRawData)
        return dwRva;
    //这是检查dwRva是不是位于文件的头部区域中

    for (wIndex = 0; wIndex FileHeader.NumberOfSections; wIndex++)
    {
        //这就是遍历所有节了,找到dwRva的节
        if (dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva             //sizeofrawdata是在文件中对齐的尺寸,这是如果dwRVa在当前节的范围内就找到了
            return (dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData);
        //这里的换算是,目的是找到函数的文件偏移地址,这个节区头的相对虚拟地址减去这个节区的相对虚拟地址等于节中的偏移加上文件的起始偏移
    }

    return 0;
}


二:注入dll

这里就很明显了,先是申请内存装DLL,再把DLL写进去,接下来就是去加载DLL,注意,CreatRemoteThread的第四个参数的强制类型转换是转换成远程函数的入口地址,第五个参数是给函数的参数。


int InjectDllToProcess(HANDLE hProcess, void* dllBuffer, size_t dllSize) {
    // 获取 DOS 头部
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)dllBuffer;
    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
        printf("Invalid DOS header.\n");
        return 0;
    }

    // 获取 NT 头部
    PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)dllBuffer + dosHeader->e_lfanew);
    if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {
        printf("Invalid NT header.\n");
        return 0;
    }

    //// 获取入口点
    //DWORD_PTR entryPoint = (DWORD_PTR)dllBase + ntHeaders->OptionalHeader.AddressOfEntryPoint;

    DWORD functionOffest = GetReflectiveLoaderOffset(dllBuffer);


    // 在目标进程中分配内存
    LPVOID remoteDllBase = VirtualAllocEx(hProcess, NULL, dllSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (remoteDllBase == NULL) {
        printf("Failed to allocate memory in target process.\n");
        return 0;
    }       

    // 将 DLL 内容写入目标进程
    if (!WriteProcessMemory(hProcess, remoteDllBase, dllBuffer, dllSize, NULL)) {
        printf("Failed to write DLL data to target process memory.\n");
        return 0;
    }
    LPTHREAD_START_ROUTINE function = (LPTHREAD_START_ROUTINE)((ULONG_PTR)remoteDllBase + functionOffest);
        // 创建远程线程执行入口点                      
        HANDLE hThread = CreateRemoteThread(hProcess, NULL0, (LPTHREAD_START_ROUTINE)function, remoteDllBase, 0NULL); 
       if (hThread == NULL) {
        printf("Failed to create remote thread.\n");
        return 0;
    }
}


源码放在最后


DLL的reflectiveinject

一:通过PEB去加载模块的kernerl32DLL

extern "C" _declspec(dllexport) int reflectiveinject(char* Buf) {
    int checkPE = 0;
    int i = 0;
    PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER)Buf;
    PIMAGE_NT_HEADERS64 ntheader = (PIMAGE_NT_HEADERS64)((ULONG_PTR)Buf + dosheader->e_lfanew);
    if (dosheader->e_magic == IMAGE_DOS_SIGNATURE) {
        if (ntheader->Signature == IMAGE_NT_SIGNATURE) {
            checkPE = 1;
        }
    }
    if (checkPE == 0) {
        //printf("this is not dll\n");
        return 0;
    }
    // ULONG_PTR Buf = caller();
   // printf("Buf address: %p\n", &Buf);
    //下面是获取kernerl32address和nt
    PVOID peb = (PEB*)__readgsqword(0x60);
    if (!peb) {
        return FALSE;
    }
    PVOID LDR = *(PVOID64**)((BYTE*)peb + 0x18);//这个指针遍历加载信息列表peb本身就是一个指针
    UNICODE_STRING* fullname;
    LIST_ENTRY* list = NULL;//好像是链表节点指针,指向模块列表的当前模块
    list = (LIST_ENTRY*)(*(PVOID64**)((BYTE*)LDR + 0x30));//30是指向存储模块名称的偏移
    LIST_ENTRY* current = list->Flink;
    wchar_t temp[13];
    HMODULE kernerl32 = NULL;
    wchar_t kerner[13] = L"kernel32.dll";
    kerner[0] = L'k';
    kerner[1] = L'e';
    kerner[2] = L'r';
    kerner[3] = L'n';
    kerner[4] = L'e';
    kerner[5] = L'l';
    kerner[6] = L'3';
    kerner[7] = L'2';
    kerner[8] = L'.';
    kerner[9] = L'd';
    kerner[10] = L'l';
    kerner[11] = L'l' ;
    kerner[12] = L'\0';

    while (current != list) {
        // 获取当前模块的入口
        PLDR_DATA_TABLE_ENTRY start = (LDR_DATA_TABLE_ENTRY*)((PCHAR)current - 0x10);

        // 检查模块有效性
        if (start && start->FullDllName.Buffer) {
            WCHAR* buffer = start->FullDllName.Buffer;
            WCHAR* zhong = buffer;
            WCHAR* jian = NULL;

            
            while (*zhong) {
                if (*zhong == L'\\') {
                    jian = zhong + 1;
                }
                zhong++;
            }

            
            if (!jian) {
                jian = buffer;
            }

            
            int match = 1;
            int i = 0;
            while (kerner[i] != L'\0' || jian[i] != L'\0') {
               WCHAR currentChar = kerner[i];
                WCHAR targetChar = jian[i];

                if (targetChar >= L'A' && targetChar <= L'Z') {
                    targetChar += 32;
                }

                // 如果字符不匹配,标记不匹配并跳出循环
                if (currentChar != targetChar) {
                    match = 0;
                    break;
                }
                i++;
            }

            // 如果匹配成功,执行相应操作
            if (match) {
                char* jiancha="find it";
                kernerl32 = (HMODULE)start->DllBase;  // 获取模块基址
                break;
            }
        }

        // 遍历下一个模块
        current = current->Flink;

        // 如果遍历完所有模块仍未找到匹配,弹出提示
        if (!current) {
            MessageBoxA(NULL"can not find the module""error", MB_OK);
            return FALSE;
        }
    }


二:遍历DLL去寻找导出函数

前面提到的注射器中也要遍历dll找导出函数,不过因为我的这个dll还没有被加载,所以肯定不能直接使用strstr这些函数,以及调用自己的函数(如果想自己写函数可以先加载节区头),这里我一共找了三个函数,这里列举一个。


  PIMAGE_DOS_HEADER KDosHeader = (PIMAGE_DOS_HEADER)((BYTE*)kernerl32);
  PIMAGE_NT_HEADERS64 Ntheader = (PIMAGE_NT_HEADERS64)((BYTE*)KDosHeader + KDosHeader->e_lfanew);
  PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)KDosHeader + Ntheader->OptionalHeader.DataDirectory[0].VirtualAddress);
  ULONG kernernum = pExportTable->NumberOfNames;
  WORD* pFunctionOrdinals = (WORD*)((BYTE*)kernerl32 + pExportTable->AddressOfNameOrdinals);

  DWORD* pFunctionAddresses = (DWORD*)((BYTE*)kernerl32 + pExportTable->AddressOfFunctions);

  DWORD* kfunname = (DWORD*)((BYTE*)KDosHeader + pExportTable->AddressOfNames);
  char* kname = NULL;
  KVirtualAlloc mymyVirtualAlloc = NULL;
  KLoadLibraryA mymyloadlibrary = NULL;
  KGetProcAddress mymyGetProcAddress = NULL;
  char a2[13] = "";
  a2[0] = 'V';
  a2[1] = 'i';
  a2[2] = 'r';
  a2[3] = 't';
  a2[4] = 'u';
  a2[5] = 'a';
  a2[6] = 'l';
  a2[7] = 'A';
  a2[8] = 'l';
  a2[9] = 'l';
  a2[10] = 'o';
  a2[11] = 'c';
  a2[12] = '\0';
  PVOID myVirtualAlloc=NULL;
  for (int i = 0; i       kname = (char*)((BYTE*)KDosHeader + kfunname[i]);
      (char*):

// 将上一步计算得到的地址转换为 char*,表示这是一个指向 C 风格字符串的指针。
// 函数名在内存中通常以 NULL 结尾,因此可以通过 char* 指针直接读取字符串
      int j = 0;//因为这个kname是以
      while (a2[j] != '\0') {
          if (kname[j] != a2[j]) {
              break// 不匹配则退出
          }
          j++;
      }//调试中发现这个kfunname是一个函数的文件路径

      if (j==12) {
          // 获取对应的函数地址
          DWORD funcOffset = pFunctionAddresses[pFunctionOrdinals[i]];
          mymyVirtualAlloc = (KVirtualAlloc)((BYTE*)kernerl32 + funcOffset);
          break;
      }
  }


三:循环加载节区头

//加载完头之后就是循环加载节区了
if (ntheader->OptionalHeader.SectionAlignment OptionalHeader.FileAlignment) {
    // printf("the structure may be wrong");
    return 0;   
}

int num = ntheader->FileHeader.NumberOfSections;
while (num) {
    int j = Sectionheader->Misc.VirtualSize % secalign;//原始节区的大小或虚拟大小,第二个参数是节区的对齐要求。就是偏移
    if (j != 0) {
        j = (Sectionheader->Misc.VirtualSize / secalign) + 1;
    }
    else {
        j = Sectionheader->Misc.VirtualSize / secalign;
    }
    DWORD dwvirsize = j * Sectionheader->Misc.VirtualSize * secalign;//是不是应该删去一个元素
    DWORD realsize = Sectionheader->SizeOfRawData > dwvirsize ? dwvirsize : Sectionheader->SizeOfRawData;
   // memmove(pAlloc + Sectionheader->VirtualAddress, (PBYTE)Buf + Sectionheader->PointerToRawData, realsize);
    void* st = (pAlloc + Sectionheader->VirtualAddress);
    void* sour = (PBYTE)Buf + Sectionheader->PointerToRawData;
    if (st         for (int i = 0; i <= realsize; i++) {
            *((char*)st + i) = *((char*)sour + i);
        }
    }
    else if (st > sour) {
        for (int i = realsize; i >= 0; i--) {
            *((char*)st + i) = *((char*)sour + i);
        }
    }
    Sectionheader = (PIMAGE_SECTION_HEADER)((PBYTE)Sectionheader + (BYTE)(sizeof(IMAGE_SECTION_HEADER)));
    num--;
}


四:循环加载重定位表


PIMAGE_BASE_RELOCATION Basereloc = (PIMAGE_BASE_RELOCATION)(ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + pAlloc);
int sizeofBasereloc = ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
if (ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) {
    do {
        PWORD TypeOffset = (WORD*)((PBYTE)Basereloc + 8);//跳过重定位快的前8个元数据,直接指向重定位块的数据
        num = (Basereloc->SizeOfBlock - 8) / 2;//这个每个重定位条目的大小是2字节,这是计算多少个重定位条目
        for (int i = 0; i             WORD type = TypeOffset[i] >> 12;
            WORD offset = TypeOffset[i] & 0xFFF;
            int differ = 0;
            if (type == 3) {
                differ = *((DWORD*)(offset + (Basereloc->VirtualAddress) + pAlloc)) - ntheader->OptionalHeader.ImageBase;
                int p = (DWORD)pAlloc + differ;
               // memmove(pAlloc + offset + Basereloc->VirtualAddress, &p, 4);
                void* est = (pAlloc + offset + Basereloc->VirtualAddress);
                void* sour = &p;
                if (est                     for (int i = 0; i <= 4; i++) {
                        *((char*)est + i) = *((char*)sour + i);
                    }
                }
                else if (est > sour) {
                    for (int i = 4; i >= 0; i--) {
                        *((char*)est + i) = *((char*)sour + i);
                    }
                }
            }
        }
        sizeofBasereloc -= Basereloc->SizeOfBlock;
        Basereloc = (PIMAGE_BASE_RELOCATION)((PBYTE)Basereloc + Basereloc->SizeOfBlock);
    } while (sizeofBasereloc);
}


五:加载导入表

///导入表的处理
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + pAlloc);

if (pImport != NULL)
{
    while (pImport->Name != NULL)
    {
        char DLLname[50] = "0";
       // strncpy(DLLname, (char*)(pImport->Name + pAlloc), 49);
        char* mu = (char*)(pImport->Name + pAlloc);
        for (int i = 0; i 49&&mu[i]!='\0'; i++) {
            DLLname[i] = mu[i];
       }
        DLLname[49] = '\0';
        HMODULE hProcess = mymyloadlibrary(DLLname);

        if (!hProcess)
        {
            char err[100];

      
            MessageBoxA(NULL, err, "Error", MB_OKCANCEL);

            return FALSE;
        }

        PIMAGE_THUNK_DATA64 pINT = (PIMAGE_THUNK_DATA64)(pImport->OriginalFirstThunk + pAlloc);
        PIMAGE_THUNK_DATA64 pIAT = (PIMAGE_THUNK_DATA64)(pImport->FirstThunk + pAlloc);


        while ((ULONG_PTR)(pINT->u1.AddressOfData) != NULL)
        {
            PIMAGE_IMPORT_BY_NAME pFucname = (PIMAGE_IMPORT_BY_NAME)(pINT->u1.AddressOfData + pAlloc);
            if (pINT->u1.AddressOfData & IMAGE_ORDINAL_FLAG32)
            {
                pIAT->u1.AddressOfData = (ULONG_PTR)(mymyGetProcAddress(hProcess, (LPCSTR)(pINT->u1.AddressOfData)));
            }
            else
            {
                pIAT->u1.AddressOfData = (ULONG_PTR)(mymyGetProcAddress(hProcess, pFucname->Name));
            }
            pINT++;
            pIAT++;
        }

        pImport++;
    }
}


六:执行main函数

  //进入EP执行main函数
  ProcMain MMain = NULL;
  MMain = (ProcMain)(ntheader->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)pAlloc);
  MMain();
  return true;
BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)

{
    MessageBox(NULLL"SUCCESS"L"great", MB_OK);
    //switch (ul_reason_for_call)
    //{
    //case DLL_PROCESS_ATTACH:
    //case DLL_THREAD_ATTACH:
    //case DLL_THREAD_DETACH:
    //case DLL_PROCESS_DETACH:
    //    break;
    //}
    
    return TRUE;
}


遇到的异常

1.vs自动生成的代码会有错误,想想可能nop掉或者说换个编译器,也有可能是全局变量的问题,这里我们先nop

跳过这个异常执行后面的用户代码再后来看看。



看第一段,代码点进去发现没有什么用,后来才知道 Visual Studio 的MSVC编译器会对类成员函数默认使用__thiscall调用约定。这是微软编译器的一种特性,特别是当处理 C++ 类成员函数时,this指针会被隐式传递。  


明确了,先学PEB和TEB寻找函数,然后再调用函数去使用,可以详细看看rdi的代码是如何运行的。


2.代码消失


这里如果改了优化,代码块可能会被vs自动识别一些冗余或者大小的代码,所以如果遇到代码突然消失(指的是在x64,ida死活找不到代码的时候),先看看这个吧。我这里消失了因为我改优化成了一些最大优化。


3.局部变量异常


这种定义因为会在下面里面继续用,所以不要放在循环里面去定义它,不然会只是一个局部变量,就会是一个空指针。


4.强转错误


请注意一些32位和64位的区别。


  1. 基础字符类型


类型

定义

说明

char

单字节字符

用于表示 ANSI 或 ASCII 字符。

wchar_t

宽字符(2 字节/4 字节)

用于表示 Unicode 字符(Windows 下为 UTF-16)。

TCHAR

宏定义的字符类型

根据字符集(ANSI/Unicode)选择charwchar_t



2. 字符串指针类型


类型

定义

说明

LPSTR

typedef char* LPSTR;

指向普通字符串(char*

)。

LPCSTR

typedef const char* LPCSTR;

指向常量普通字符串(const char*

)。

LPWSTR

typedef wchar_t* LPWSTR;

指向宽字符字符串(wchar_t*

)。

LPCWSTR

typedef const wchar_t* LPCWSTR;

指向常量宽字符字符串(const wchar_t*

)。

LPTSTR

typedef TCHAR* LPTSTR;

指向TCHAR

字符串。

LPCTSTR

typedef const TCHAR* LPCTSTR;

指向常量TCHAR

字符串


5.位数错误


int differ = *((DWORD*)(offset + (Basereloc->VirtualAddress) + pAlloc)) - ntheader->OptionalHeader.ImageBase;
int p = (DWORD)pAlloc + differ;


◆使用的是DWORD(32 位无符号整数)作为地址计算和存储数据。


问题:如果运行在 64 位程序中,DWORD不足以表示完整的 64 位地址,这可能导致重定位出错。


◆应该是 ULONG_PTR  可能会更好,但是这个也可以


32 位平台ULONG_PTR定义为一个 32 位的无符号整数(通常是unsigned long)。


64 位平台ULONG_PTR定义为一个 64 位的无符号整数(通常是unsigned long longunsigned __int64)。


DWORD

适用于存储状态码、32 位整数等。

在 64 位程序中不能表示完整指针或地址,需用ULONG_PTR

替代。

ULONG_PTR

适合跨平台存储指针、地址或大小。

无明显不足,是处理跨平台指针数据的最佳选择。

SIZE_T

用于内存分配或大小计算。

ULONG_PTR

,但更专注于大小而非指针。


ASCII 和 Unicode 的对比表


Unicode和宽字符匹配,一般一起用,windowsAPI要求使用的都是宽字符。


特性

ASCII

Unicode

字符范围

0~127 或 0~255

0~1,114,111

存储方式

1 字节

UTF-8: 1~4 字节
UTF-16: 2~4 字节
UTF-32: 4 字节

支持语言

仅支持英语等基本符号

支持几乎所有语言和符号

是否向下兼容

向下兼容 ASCII

主要用途

英文字符和控制符

全球化应用,适配多语言系统


手动实现memcpy:

cpp


复制代码
void* est = (pAlloc + offset + Basereloc->VirtualAddress);
void* sour = &p;

if (est     for (int i = 0; i <= 4; i++) {
        *((char*)est + i) = *((char*)sour + i);
    }
} else if (est > sour) {
    for (int i = 4; i >= 0; i--) {
        *((char*)est + i) = *((char*)sour + i);
    }
}


◆手动实现了类似memcpy的功能,但逐字节复制,分成了从前向后和从后向前两种情况。


问题:代码显得冗长,且对于 64 位程序不支持8 字节地址字段


◆使用简单的循环逐字节复制,但没有处理8 字节地址的情况。


◆如果是 64 位程序,代码仍需调整以支持ULONG_PTR的完整长度。。


手动实现strncpy

char *strncpy(char *dest, const char *src, size_t n);


如果源字符串的长度小于n,那么目标数组的剩余部分会用'\0'填充,确保目标字符串是正确的 C 字符串(以\0结尾)。  


strncpy可以防止因源字符串过长导致的缓冲区溢出,尤其在处理用户输入或不确定字符串长度时比较有用。  


memcpy用于复制任意类型的内存块,并不关心目标数组是否是字符串。


 char DLLname[50];
// strncpy(DLLname, (char*)(pImport->Name + pAlloc), 49);
 char* mu = (char*)(pImport->Name + pAlloc);
 for (int i = 0; i 50&&DLLname[i]!='\0'; i++) {
     DLLname[i] = mu[i];
}
 DLLname[i] = '\0';


手动实现memmove


// memmove(pAlloc + offset + Basereloc->VirtualAddress, &p, 4);
 void* dest = (pAlloc + offset + Basereloc->VirtualAddress);
 void* sour = &p;
 if (dest      for (int i = 0; i <= 4; i++) {
         *((char*)dest + i) = *((char*)sour + i);
     }
 }
 else if (dest > sour) {
     for (int i = 4; i >= 0; i--) {
         *((char*)dest + i) = *((char*)sour + i);
     }
 }


源码

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include 
    #include "pch.h"
    #include 
    #include 
    #include 
    //#pragma intrinsic( _ReturnAddress )
    //__declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); }
    #include 
    

    typedef struct _UNICODE_STRING {
        USHORT Length;
        USHORT MaximumLength;
        PWSTR  Buffer;
    } UNICODE_STRING, * PUNICODE_STRING;

    typedef struct _LDR_DATA_TABLE_ENTRY {
       // LIST_ENTRY InLoadOrderLinks;              tmd为什么这个不要啊,给我搞了半天,草
        LIST_ENTRY InMemoryOrderLinks;
        LIST_ENTRY InInitializationOrderLinks;
        PVOID      DllBase;              // 模块基地址
        PVOID      EntryPoint;
        ULONG      SizeOfImage;
        UNICODE_STRING FullDllName;      // 完整路径
        UNICODE_STRING BaseDllName;      // 模块名称
    } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;

    typedef struct _PEB_LDR_DATA {
        ULONG Length;                      // 结构体的长度
        BOOLEAN Initialized;               // 初始化标志
        HANDLE SsHandle;                   // 保留字段
        LIST_ENTRY InLoadOrderModuleList;  // 加载顺序链表头(偏移 0x10)
        LIST_ENTRY InMemoryOrderModuleList;// 内存顺序链表头(偏移 0x30)
        LIST_ENTRY InInitializationOrderModuleList; // 初始化顺序链表头(偏移 0x40)
    } PEB_LDR_DATA, * PPEB_LDR_DATA;

    typedef struct _PEB {
        BYTE Reserved1[2];           // 保留字段
        BYTE BeingDebugged;          // 调试标志
        BYTE Reserved2[1];           // 保留字段
        PVOID Reserved3[2];          // 保留字段
        PPEB_LDR_DATA Ldr;           // 指向模块加载信息的指针(偏移 0x18)
        // 省略其他不相关字段
    } PEB, * PPEB;
    //PEB* getpeb() {
    //#ifdef _WIN64
    //    return (PEB*)__readgsqword(0x60); // x64 获取 PEB
    //#else
    //    return (PEB*)__readfsdword(0x30); // x86 获取 PEB
    //#endif
    //}

    typedef HMODULE(WINAPI* KLoadLibraryA)(LPCSTR);

    typedef FARPROC(WINAPI* KGetProcAddress)(HMODULE, LPCSTR);

    typedef LPVOID(WINAPI* KVirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD);
    typedef   BOOL(__cdecl* ProcMain)();
    extern "C" _declspec(dllexport) int reflectiveinject(char* Buf) {
        int checkPE = 0;
        int i = 0;
        PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER)Buf;
        PIMAGE_NT_HEADERS64 ntheader = (PIMAGE_NT_HEADERS64)((ULONG_PTR)Buf + dosheader->e_lfanew);
        if (dosheader->e_magic == IMAGE_DOS_SIGNATURE) {
            if (ntheader->Signature == IMAGE_NT_SIGNATURE) {
                checkPE = 1;
            }
        }
        if (checkPE == 0) {
            //printf("this is not dll\n");
            return 0;
        }
        // ULONG_PTR Buf = caller();
       // printf("Buf address: %p\n", &Buf);
        //下面是获取kernerl32address和nt
        PVOID peb = (PEB*)__readgsqword(0x60);
        if (!peb) {
            return FALSE;
        }
        PVOID LDR = *(PVOID64**)((BYTE*)peb + 0x18);//这个指针遍历加载信息列表peb本身就是一个指针
        UNICODE_STRING* fullname;
        LIST_ENTRY* list = NULL;//好像是链表节点指针,指向模块列表的当前模块
        list = (LIST_ENTRY*)(*(PVOID64**)((BYTE*)LDR + 0x30));//30是指向存储模块名称的偏移
        LIST_ENTRY* current = list->Flink;
        wchar_t temp[13];
        HMODULE kernerl32 = NULL;
        wchar_t kerner[13] = L"kernel32.dll";
        kerner[0] = L'k';
        kerner[1] = L'e';
        kerner[2] = L'r';
        kerner[3] = L'n';
        kerner[4] = L'e';
        kerner[5] = L'l';
        kerner[6] = L'3';
        kerner[7] = L'2';
        kerner[8] = L'.';
        kerner[9] = L'd';
        kerner[10] = L'l';
        kerner[11] = L'l';
        kerner[12] = L'\0';

        while (current != list) {
            // 获取当前模块的入口
            PLDR_DATA_TABLE_ENTRY start = (LDR_DATA_TABLE_ENTRY*)((PCHAR)current - 0x10);

            // 检查模块有效性
            if (start && start->FullDllName.Buffer) {
                WCHAR* buffer = start->FullDllName.Buffer;
                WCHAR* zhong = buffer;
                WCHAR* jian = NULL;

                while (*zhong) {
                    if (*zhong == L'\\') {
                        jian = zhong + 1;
                    }
                    zhong++;
                }

                if (!jian) {
                    jian = buffer;
                }

                
                int match = 1;
                int i = 0;
                while (kerner[i] != L'\0' || jian[i] != L'\0') {
                   WCHAR currentChar = kerner[i];
                    WCHAR targetChar = jian[i];

                    if (targetChar >= L'A' && targetChar <= L'Z') {
                        targetChar += 32;
                    }

                    // 如果字符不匹配,标记不匹配并跳出循环
                    if (currentChar != targetChar) {
                        match = 0;
                        break;
                    }
                    i++;
                }

                // 如果匹配成功,执行相应操作
                if (match) {
                    char* jiancha="find it";
                    kernerl32 = (HMODULE)start->DllBase;  // 获取模块基址
                    break;
                }
            }

            // 遍历下一个模块
            current = current->Flink;

            // 如果遍历完所有模块仍未找到匹配,弹出提示
            if (!current) {
                MessageBoxA(NULL"can not find the module""error", MB_OK);
                return FALSE;
            }
        }
    
        PIMAGE_DOS_HEADER KDosHeader = (PIMAGE_DOS_HEADER)((BYTE*)kernerl32);
        PIMAGE_NT_HEADERS64 Ntheader = (PIMAGE_NT_HEADERS64)((BYTE*)KDosHeader + KDosHeader->e_lfanew);
        PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)KDosHeader + Ntheader->OptionalHeader.DataDirectory[0].VirtualAddress);
        ULONG kernernum = pExportTable->NumberOfNames;
        WORD* pFunctionOrdinals = (WORD*)((BYTE*)kernerl32 + pExportTable->AddressOfNameOrdinals);

        DWORD* pFunctionAddresses = (DWORD*)((BYTE*)kernerl32 + pExportTable->AddressOfFunctions);

        DWORD* kfunname = (DWORD*)((BYTE*)KDosHeader + pExportTable->AddressOfNames);
        char* kname = NULL;
        KVirtualAlloc mymyVirtualAlloc = NULL;
        KLoadLibraryA mymyloadlibrary = NULL;
        KGetProcAddress mymyGetProcAddress = NULL;
        char a2[13] = "";
        a2[0] = 'V';
        a2[1] = 'i';
        a2[2] = 'r';
        a2[3] = 't';
        a2[4] = 'u';
        a2[5] = 'a';
        a2[6] = 'l';
        a2[7] = 'A';
        a2[8] = 'l';
        a2[9] = 'l';
        a2[10] = 'o';
        a2[11] = 'c';
        a2[12] = '\0';
        PVOID myVirtualAlloc=NULL;
        for (int i = 0; i             kname = (char*)((BYTE*)KDosHeader + kfunname[i]);
            int j = 0;
            while (a2[j] != '\0') {
                if (kname[j] != a2[j]) {
                    break// 不匹配则退出
                }
                j++;
            }

            if (j==12) {
                // 获取对应的函数地址
                DWORD funcOffset = pFunctionAddresses[pFunctionOrdinals[i]];
                mymyVirtualAlloc = (KVirtualAlloc)((BYTE*)kernerl32 + funcOffset);
                break;
            }
        }
       // KVirtualAlloc mymyVirtualAlloc = (KVirtualAlloc)myVirtualAlloc;
       // printf("fuckfuckfuck");
        char a3[15] = "";
        a3[0] = 'G';
        a3[1 ] = 'e';
        a3[2] = 't';
        a3[3] = 'P';
        a3[4] = 'r';
        a3[5] = 'o';
        a3[6] = 'c';
        a3[7] = 'A';
        a3[8] = 'd';
        a3[9] = 'd';
        a3[10] = 'r';
        a3[11] = 'e';
        a3[12] = 's';
        a3[13] = 's';
        a3[14] = '\0';

        PVOID myGetProcAddress=NULL;
        for (int i = 0; i             kname = (char*)((BYTE*)KDosHeader + kfunname[i]);
            int j = 0;
            while (a3[j] != '\0') {
                if (kname[j] != a3[j]) {
                    break// 不匹配则退出
                }
                j++;
            }


            if (j==14) {
                // 获取对应的函数地址
                DWORD funcOffset = pFunctionAddresses[pFunctionOrdinals[i]];
                mymyGetProcAddress = (KGetProcAddress)((BYTE*)KDosHeader + funcOffset);
                break;
            }
        }
       
        char a4[12] = "";
        a4[0] = 'L';
        a4[1] = 'o';
        a4[2] = 'a';
        a4[3] = 'd';
        a4[4] = 'L';
        a4[5] = 'i';
        a4[6] = 'b';
        a4[7] = 'r';
        a4[8] = 'a';
        a4[9] = 'r';
        a4[10] = 'y';
        a4[11] = '\0';
        PVOID myloadlibrary=NULL;
        for (int i = 0; i             kname = (char*)((BYTE*)KDosHeader + kfunname[i]);
            int j = 0;
            while (a4[j] != '\0') {
                if (kname[j] != a4[j]) {
                    break// 不匹配则退出
                }
                j++;
            }

           

            if (j==11) {
                // 获取对应的函数地址
                DWORD funcOffset = pFunctionAddresses[pFunctionOrdinals[i]];
                mymyloadlibrary = (KLoadLibraryA)((BYTE*)KDosHeader + funcOffset);//留个痕迹,为什么PUCHAR不行
                break;
            }
        }
        if (mymyVirtualAlloc == 0) {
            MessageBoxA(NULL"where is the mymyVirtualAlloc""no", MB_OK);
        }
        if (mymyloadlibrary == 0) {
            MessageBoxA(NULL"where is the lodalibrary""no", MB_OK);
        }
        if (mymyGetProcAddress == 0) {
            MessageBoxA(NULL"where is the mymyGetProcAddress""no", MB_OK);
        }










        /*  PIMAGE_SECTION_HEADER SectionHeader=(PIMAGE_SECTION_HEADER)((PBYTE)(ntheader)+0x18+(ntheader->FileHeader.SizeOfOptionalHeader))*/
        PIMAGE_SECTION_HEADER Sectionheader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&ntheader->OptionalHeader) + ntheader->FileHeader.SizeOfOptionalHeader);
        DWORD secalign = ntheader->OptionalHeader.SectionAlignment;//赋值内存偏移
        DWORD filealign = ntheader->OptionalHeader.FileAlignment;//赋值文件偏移
        PBYTE pAlloc = (PBYTE)mymyVirtualAlloc(NULL, ntheader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (pAlloc == NULL) {
            // printf("perhaps we can not use the virtual");
            return 0;
        }
      //  memset(pAlloc, 0, ntheader->OptionalHeader.SizeOfImage);
        void* t = pAlloc;
        for (int i = 0; i OptionalHeader.SizeOfImage); i++) {
            *((char*)t + i) = 0;
        }
        DWORD dwsizeofHeader = ntheader->OptionalHeader.SizeOfHeaders;
        //直接赋值文件头的大小
        //memmove(pAlloc, (PBYTE)Buf, dwsizeofHeader);下面是我的手动实现memmove的过程
         void* dest = pAlloc;
        void* sour = (PBYTE)Buf;
        if (dest             for (int i = 0; i <= dwsizeofHeader; i++) {
                *((char*)dest + i) = *((char*)sour + i);
            }
        }
        else if (dest > sour) {
            for (int i = dwsizeofHeader; i >= 0; i--) {
                *((char*)dest + i) = *((char*)sour + i);
            }
        }
        //加载完头之后就是循环加载节区了
        if (ntheader->OptionalHeader.SectionAlignment OptionalHeader.FileAlignment) {
            // printf("the structure may be wrong");
            return 0;   
        }

        int num = ntheader->FileHeader.NumberOfSections;
        while (num) {
            int j = Sectionheader->Misc.VirtualSize % secalign;//原始节区的大小或虚拟大小,第二个参数是节区的对齐要求。就是偏移
            if (j != 0) {
                j = (Sectionheader->Misc.VirtualSize / secalign) + 1;
            }
            else {
                j = Sectionheader->Misc.VirtualSize / secalign;
            }
            DWORD dwvirsize = j * Sectionheader->Misc.VirtualSize * secalign;//是不是应该删去一个元素
            DWORD realsize = Sectionheader->SizeOfRawData > dwvirsize ? dwvirsize : Sectionheader->SizeOfRawData;
           // memmove(pAlloc + Sectionheader->VirtualAddress, (PBYTE)Buf + Sectionheader->PointerToRawData, realsize);
            void* st = (pAlloc + Sectionheader->VirtualAddress);
            void* sour = (PBYTE)Buf + Sectionheader->PointerToRawData;
            if (st                 for (int i = 0; i <= realsize; i++) {
                    *((char*)st + i) = *((char*)sour + i);
                }
            }
            else if (st > sour) {
                for (int i = realsize; i >= 0; i--) {
                    *((char*)st + i) = *((char*)sour + i);
                }
            }
            Sectionheader = (PIMAGE_SECTION_HEADER)((PBYTE)Sectionheader + (BYTE)(sizeof(IMAGE_SECTION_HEADER)));
            num--;
        }
        //加载完节区之后就是加载重定位表了
       /* IMAGE_BASE_RELOCATION STRUC 【基址重定位位于数据目录表的第六项,共8 + N字节】
        {
        +00 h DWORD VirtualAddress; 重定位数据开始的RVA 地址,重定位地址加上这个值就是完整的RVA地址
        + 04 h DWORD SizeOfBlock; 重定位块得长度,标识重定向字段个数
        + 08 h WORD TypeOffset; 重定项位数组相对虚拟RVA,个数动态分配
        };
        IMAGE_BASE_RELOCATION ENDS*/

        PIMAGE_BASE_RELOCATION Basereloc = (PIMAGE_BASE_RELOCATION)(ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + pAlloc);
        int sizeofBasereloc = ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
        if (ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) {
            do {
                PWORD TypeOffset = (WORD*)((PBYTE)Basereloc + 8);//跳过重定位快的前8个元数据,直接指向重定位块的数据
                num = (Basereloc->SizeOfBlock - 8) / 2;//这个每个重定位条目的大小是2字节,这是计算多少个重定位条目
                for (int i = 0; i                     WORD type = TypeOffset[i] >> 12;
                    WORD offset = TypeOffset[i] & 0xFFF;
                    int differ = 0;
                    if (type == 3) {
                        differ = *((DWORD*)(offset + (Basereloc->VirtualAddress) + pAlloc)) - ntheader->OptionalHeader.ImageBase;
                        int p = (DWORD)pAlloc + differ;
                       // memmove(pAlloc + offset + Basereloc->VirtualAddress, &p, 4);
                        void* est = (pAlloc + offset + Basereloc->VirtualAddress);
                        void* sour = &p;
                        if (est                             for (int i = 0; i <= 4; i++) {
                                *((char*)est + i) = *((char*)sour + i);
                            }
                        }
                        else if (est > sour) {
                            for (int i = 4; i >= 0; i--) {
                                *((char*)est + i) = *((char*)sour + i);
                            }
                        }
                    }
                }
                sizeofBasereloc -= Basereloc->SizeOfBlock;
                Basereloc = (PIMAGE_BASE_RELOCATION)((PBYTE)Basereloc + Basereloc->SizeOfBlock);
            } while (sizeofBasereloc);
        }




        ///导入表的处理
        PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + pAlloc);

        if (pImport != NULL)
        {
            while (pImport->Name != NULL)
            {
                char DLLname[50] = "0";
               // strncpy(DLLname, (char*)(pImport->Name + pAlloc), 49);
                char* mu = (char*)(pImport->Name + pAlloc);
                for (int i = 0; i 49&&mu[i]!='\0'; i++) {
                    DLLname[i] = mu[i];
               }
                DLLname[49] = '\0';
                HMODULE hProcess = mymyloadlibrary(DLLname);

                if (!hProcess)
                {
                    char err[100];

              
                    MessageBoxA(NULL, err, "Error", MB_OKCANCEL);

                    return FALSE;
                }

                PIMAGE_THUNK_DATA64 pINT = (PIMAGE_THUNK_DATA64)(pImport->OriginalFirstThunk + pAlloc);
                PIMAGE_THUNK_DATA64 pIAT = (PIMAGE_THUNK_DATA64)(pImport->FirstThunk + pAlloc);


                while ((ULONG_PTR)(pINT->u1.AddressOfData) != NULL)
                {
                    PIMAGE_IMPORT_BY_NAME pFucname = (PIMAGE_IMPORT_BY_NAME)(pINT->u1.AddressOfData + pAlloc);
                    if (pINT->u1.AddressOfData & IMAGE_ORDINAL_FLAG32)
                    {
                        pIAT->u1.AddressOfData = (ULONG_PTR)(mymyGetProcAddress(hProcess, (LPCSTR)(pINT->u1.AddressOfData)));
                    }
                    else
                    {
                        pIAT->u1.AddressOfData = (ULONG_PTR)(mymyGetProcAddress(hProcess, pFucname->Name));
                    }
                    pINT++;
                    pIAT++;
                }

                pImport++;
            }
        }


        //进入EP执行main函数
        ProcMain MMain = NULL;
        MMain = (ProcMain)(ntheader->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)pAlloc);
        MMain();
        return true;
    }



    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )

    {
        MessageBox(NULLL"SUCCESS"L"great", MB_OK);
        return TRUE;
    }


#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
#include 
#include "load.h"

//int main() {
// int c = Add(5, 10);
// printf("%d", c);
//
//
// return 0;
//}
// // 读取 DLL 文件到内存
// 在代码中定义宏
  // 手动定义 64 位宏
#define WIN_X64

DWORD RVA(DWORD dwRva, UINT_PTR BaseAddress)
{//这个代码是将相对虚拟地址RVA转换成文件的偏移量
    WORD wIndex = 0;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    PIMAGE_NT_HEADERS pNtHeaders = NULL;

    pNtHeaders = (PIMAGE_NT_HEADERS)(BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew);

    pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader);
    //这个是找节区头,可选头加上可选头的大小,下一个就是节区表头
    //就是查找给的RVA是属于哪个节区,其目的就是找到文件偏移地址
    if (dwRva 0].PointerToRawData)
        return dwRva;
    //这是检查dwRva是不是位于文件的头部区域中

    for (wIndex = 0; wIndex FileHeader.NumberOfSections; wIndex++)
    {
        //这就是遍历所有节了,找到dwRva的节
        if (dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva             //sizeofrawdata是在文件中对齐的尺寸,这是如果dwRVa在当前节的范围内就找到了
            return (dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData);
        //这里的换算是,目的是找到函数的文件偏移地址,这个节区头的相对虚拟地址减去这个节区的相对虚拟地址等于节中的偏移加上文件的起始偏移
    }

    return 0;
}
//写一个函数来加载我们的导出函数的偏移
DWORD GetReflectiveLoaderOffset(VOID* lpReflectiveDllBuffer)
{
    UINT_PTR BaseAddress = 0;
    UINT_PTR uiNT = 0;
    UINT_PTR uiNameArray = 0;
    UINT_PTR uiAddressArray = 0;
    UINT_PTR uiNameOrdinals = 0;
    DWORD dwCounter = 0;
#ifdef WIN_X64
    DWORD dwCompiledArch = 2;
#else
    // This will catch Win32 and WinRT.
    DWORD dwCompiledArch = 1;
#endif

    BaseAddress = (UINT_PTR)lpReflectiveDllBuffer;

    uiNT = BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew;

    //这里是主要判断当前的位数于dll位数是否一致
    if (((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.Magic == 0x010B// PE32
    {
        if (dwCompiledArch != 1)
            return 0;
    }
    else if (((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.Magic == 0x020B// PE64
    {
        if (dwCompiledArch != 2)





请到「今天看啥」查看全文