WindowsPE文件格式入门05.PE加载器LoadPE

https://bpsend.net/thread-316-1-1.html

LoadPE - pe 加载器 壳的前身

如果想访问一个程序运行起来的内存,一种方法就是跨进程读写内存,但是跨进程读写内存需要来回调用api,不如直接访问地址来得方便,那么如果我们需要直接访问地址,该怎么做呢?.需要把dll注进程,注进去的代码跟他在同一块进程里面,这样我们就可以直接访问这个进程的地址,但是不想注入,也不想跨进程读写地址,就直接读进程地址,有什么方法呢?如果把导入表里面加一个dll,这样很容易检查出来,模块里一遍历,就可容易看到了, 其实我们可以反其道行之,换种思路,不是往他进程里面塞东西,而是把他加载到我们进程里面.,这个时候再去访问进程内存其实就是访问我们自己的内存.
1.系统加载exe的流程
  • 准备一个新的内存;
  • 按照顺序把节表内容映射进内存;
  • 填写导入表。
2.LoadPE的目的
  • 可以在自己进程更改目标PE的内存。
3.LoadPE的重点
  • 1.在自己代码前留出足够空间--目标进程的SizeofImage;
  • 2.更改自己程序的ImageBase加载到目标ImageBase处:/base:0x。

img

这样,目标进程的PE头就占据了我们自己进程的 PE头,他的数据节就覆盖了我们自己的数据节,即目标进程的数据就会覆盖我们自己进程的数据,因此我们需要 把我们的代码往后移,给 目标进程 留出足够的空间

4.LoadPE的实现思路
  • 设置我们进程的 ImageBase 和 目标进程 ImageBase 保持一致
  • 我们需要把我们的代码往后移,腾出来的内存可以放目标程序
  • 读目标进程的数据,按照节表拷贝数据帮他处理导入表
  • 执行目标进程代码。
5.LoadPE的汇编实现
  1. 用winhex查看目标进程的 ImageBase 和 SizeofImage
  2. 新建工程,并且在工程选项设置 自己工程 的 ImageBase 与目标进程的一致
  3. 后移自己的代码,可以在开头定义 SizeofImage 大小的全局变量 或者通过指令 org 偏移调整指令

注意,很多 C 库函数 并不会 保存 ecx , edx 环境,自己使用前记得先保存

进程的模块基址和 数据大小可以通过 winhex看

img

.586
.model flat,stdcall
option casemap:noneinclude windows.incinclude user32.incinclude kernel32.incinclude msvcrt.incincludelib user32.libincludelib kernel32.libincludelib msvcrt.libIMAGE_SIZE equ 20000h     ;往后移的大小,即目标进程的SizeofImage.datag_szFile db "winmine.exe", 0    ;要读取的进程.codeorg IMAGE_SIZE LoadPe procLOCAL @dwImageBase:DWORD       ;自己进程的模块基址LOCAL @hFile:HANDLE            ;文件句柄LOCAL @hFileMap:HANDLE         ;映射句柄LOCAL @pPEBuf:LPVOID           ;映射文件的缓冲地址LOCAL @pDosHdr:ptr IMAGE_DOS_HEADER      ;目标进程的dos头LOCAL @pNTHdr:ptr IMAGE_NT_HEADERS       ;目标进程的NT头LOCAL @pSecHdr:ptr IMAGE_SECTION_HEADER  ;目标进程的节表LOCAL @dwNumOfSecs:DWORD                 ;目标进程的节表数量LOCAL @pImpHdr:ptr IMAGE_IMPORT_DESCRIPTOR   ;目标进程的导入表LOCAL @dwSizeOfHeaders:DWORD                 ;目标进程的选项头大小LOCAL @dwOldProc:DWORD                       ;旧的内存属性LOCAL @hdrZeroImp:IMAGE_IMPORT_DESCRIPTOR    ;导入表结束标志,所有项全0LOCAL @hDll:HMODULE                          ;加载dll的句柄LOCAL @dwOep:DWORD                           ;进程的入口地址;判断导入表结束的标志清0invoke RtlZeroMemory, addr @hdrZeroImp, size IMAGE_IMPORT_DESCRIPTOR;自己的模块基址invoke GetModuleHandle, NULLmov @dwImageBase, eax;解析PE文件,获取表;打开文件invoke CreateFile, offset g_szFile, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL;check ....mov @hFile, eax   ;保存文件句柄invoke CreateFileMapping, @hFile, NULL, PAGE_READONLY, 0, 0, NULL   ;创建文件映射;checkmov @hFileMap, eax    ;创建文件映射句柄invoke MapViewOfFile, @hFileMap, FILE_MAP_READ, 0, 0, 0      ;将整个文件映射进内存;check mov @pPEBuf, eax      ;保存映射文件内存的地址;解析目标进程;目标进程的 dos 头mov eax, @pPEBuf    mov @pDosHdr, eax;目标进程的 nt头mov esi, @pDosHdrassume esi:ptr IMAGE_DOS_HEADERmov eax, @pPEBufadd eax, [esi].e_lfanew   ;获取nt头的偏移地址mov @pNTHdr, eaxmov esi, @pNTHdrassume esi:ptr IMAGE_NT_HEADERS;选项头信息mov eax, [esi].OptionalHeader.SizeOfHeaders    ;获取选项头大小mov @dwSizeOfHeaders, eax;进程的入口地址  =  进程的内存偏移地址 + 模块基址mov eax, [esi].OptionalHeader.AddressOfEntryPointadd eax, @dwImageBasemov @dwOep, eax;节表  地址: 选项头地址+大小movzx eax, [esi].FileHeader.NumberOfSectionsmov @dwNumOfSecs,eaxlea ebx, [esi].OptionalHeader;获取选项头大小:用于定位节表位置=选项头地址+选项头大小movzx eax, [esi].FileHeader.SizeOfOptionalHeader   ;把 word 转为 dwordadd eax, ebxmov @pSecHdr, eax   ;保存节表地址;修改内存属性invoke VirtualProtect, @dwImageBase, IMAGE_SIZE, PAGE_EXECUTE_READWRITE, addr @dwOldProc;拷贝PE头  从映射内存拷贝到 自己进程的最开始处 invoke crt_memcpy, @dwImageBase, @pPEBuf, @dwSizeOfHeaders;按照节表,拷贝节区数据mov esi, @pSecHdrassume esi:ptr IMAGE_SECTION_HEADERxor ecx, ecx.while ecx < @dwNumOfSecs   ;遍历节表;目标mov edi, @dwImageBaseadd edi, [esi].VirtualAddress  ;获取节的内存地址 + 模块地址 就是内存中的绝对地址;源mov ebx, @pPEBufadd ebx, [esi].PointerToRawData  ;获取指定进程的节数据的偏移地址  映射的首地址 + 文件偏移地址;大小[esi].SizeOfRawData;拷贝  注意,很多 C 库函数 并不会 保存 ecx ,edx 环境,自己使用前记得先保存push ecxpush edxinvoke crt_memcpy, edi, ebx, [esi].SizeOfRawData   ;将目标进程的节数据拷贝进自己的进程pop edxpop ecxinc ecx      ;计数++add esi, size IMAGE_SECTION_HEADER  ;指针移动.endw;获取导入表  如果在前面获取导入表信息,那么就需要对内存地址和文件地址做转化比较麻烦;但是把数据拷贝到我们进程之后只需要访问内存进程就可以了mov esi, @pNTHdrassume esi:ptr IMAGE_NT_HEADERS;获取导入表地址 ,数组的第二个元素的第一个成员 mov eax, [esi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT*8].VirtualAddressadd eax, @dwImageBase   ;获取导入表在进程的绝对地址  内存偏移 + 模块基址mov @pImpHdr, eax       ;保存导入表的地址;处理导入表mov esi, @pImpHdrassume esi:ptr IMAGE_IMPORT_DESCRIPTOR.while TRUE     ;遍历导入表;判断结束,全0项结束invoke crt_memcmp, esi, addr @hdrZeroImp.if eax == 0.break.endif;判断字段,为空则结束.if [esi].Name1 == NULL || [esi].FirstThunk == NULL.break.endif ;加载dllmov eax, [esi].Name1add eax, @dwImageBasepush ecxpush edxinvoke LoadLibrary, eax   ;根据dll名加载 dll pop edxpop ecx;check              如果此时为空加说明无法找到dllmov @hDll, eax      ;保存dll的模句柄;获取导入地址表,IATmov ebx, [esi].FirstThunkadd ebx, @dwImageBase;获取导入名称表,INTmov edi, ebx.if [esi].OriginalFirstThunk != NULLmov edi, [esi].OriginalFirstThunkadd edi, @dwImageBase          .endif;遍历导入名称表.while dword ptr [edi] != 0.if dword ptr [edi] & 80000000h   ;判断最高位是否为1;序号导入,获取序号mov edx, dword ptr [edi]and edx, 0ffffh               ;获取低 word .else;名称导入mov edx, dword ptr [edi]add edx, @dwImageBaseadd edx, 2                  ;名称前面有2个无用字节.endif;获取dll导入函数进程加载后地址push ecxpush edxinvoke GetProcAddress, @hDll, edxpop edxpop ecx;check;把地址存入 INT 表mov dword ptr [ebx], eaxadd ebx, 4add edi, 4.endwadd esi, size IMAGE_IMPORT_DESCRIPTOR.endw;清理invoke UnmapViewOfFile,@pPEBufinvoke CloseHandle,@hFileMapinvoke CloseHandle,@hFile; 执行加载的pe的代码jmp @dwOepretLoadPe endpstart:invoke LoadPeinvoke ExitProcess,0end start

需要合并节

.text,ERW

img

C++版:

#include <windows.h>
#include <concrt.h>
#include <iostream>
using namespace std;#define IMAGE_SIZE 0x5000//留空的全局变量
char szBuff[IMAGE_SIZE] = { 1 };#if 1
char g_szExeName[] = "PE.exe";  //需要加载的PE路径LPVOID lpMapAddr = NULL;HANDLE LoadPe()
{DWORD  dwOldProc = 0;PIMAGE_IMPORT_DESCRIPTOR pImpHdr = NULL;IMAGE_IMPORT_DESCRIPTOR  zeroImp = { 0 };HANDLE hDll = NULL;PIMAGE_THUNK_DATA pTmpThunk = NULL;DWORD  dwPFNAddr = 0;DWORD  dwIAT = 0;// 获取模块句柄HANDLE hInst = GetModuleHandle(NULL);// 读取文件HANDLE hFile = CreateFile(g_szExeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE){return 0;}// 创建文件映射对象HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);if (hFileMap == NULL){CloseHandle(hFile);return 0;}void* lpMapAddr = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);if (lpMapAddr == NULL){CloseHandle(hFileMap);CloseHandle(hFile);return 0;}// 拷贝PE头PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpMapAddr;PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)lpMapAddr + pDosHeader->e_lfanew);DWORD dwSizeOfHeaders = pNtHeader->OptionalHeader.SizeOfHeaders;DWORD dwNumOfSection = pNtHeader->FileHeader.NumberOfSections;//获取节表首地址  (选项头地址+ 大小)PIMAGE_SECTION_HEADER pSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader->FileHeader.SizeOfOptionalHeader + (DWORD)(&pNtHeader->OptionalHeader));DWORD dwOep = (DWORD)hInst + pNtHeader->OptionalHeader.AddressOfEntryPoint;// 更改内存属性VirtualProtect(hInst, IMAGE_SIZE, PAGE_EXECUTE_READWRITE, &dwOldProc);//拷贝PE头memcpy(hInst, lpMapAddr, dwSizeOfHeaders);// 拷贝拷贝节区数据DWORD i = 0;while (dwNumOfSection > i){//拷贝数据DWORD pDst = (DWORD)hInst + (DWORD)pSecHdr->VirtualAddress;DWORD pSrc = (DWORD)lpMapAddr + (DWORD)pSecHdr->PointerToRawData;//DWORD pSrc = (DWORD)pSecHdr;memcpy((void*)pDst, (void*)pSrc, pSecHdr->SizeOfRawData);int nSecHdrSzie = sizeof(IMAGE_SECTION_HEADER);pSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pSecHdr + (DWORD)nSecHdrSzie);i++;}//获取导入表地址pImpHdr = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNtHeader->OptionalHeader.DataDirectory[1].VirtualAddress + (DWORD)hInst);// 处理导入表while (TRUE){// 遇到全0项,遍历结束 int nRet = memcmp(pImpHdr, &zeroImp, sizeof(IMAGE_IMPORT_DESCRIPTOR));if (nRet == 0){break;}//判断字段, 为空则结束if (pImpHdr->Name == NULL || pImpHdr->FirstThunk == NULL){break;}DWORD pNameAddre = (DWORD)pImpHdr->Name + (DWORD)hInst;// 加载dllHMODULE hDll = LoadLibrary((LPCSTR)pNameAddre);if (hDll == NULL){break;}DWORD pFunAddr = 0;DWORD pIAT = (DWORD)pImpHdr->FirstThunk + (DWORD)hInst;DWORD pINT = (DWORD)pImpHdr->OriginalFirstThunk;if (pINT != 0){pFunAddr = pINT + (DWORD)hInst;}else{pFunAddr = pIAT;}// 遍历导入名称表while (true){DWORD pAddr = *(DWORD*)pFunAddr;if (pAddr == 0){break;}DWORD  pFun = 0;if (pAddr & 0x80000000){//序号导入, 获取序号pFun = pAddr & 0xffff;}else{pFun = pAddr + 2 + (DWORD)hInst;}DWORD  dwPFNAddr = (DWORD)GetProcAddress(hDll, (LPCSTR)LOWORD(pFun));*(DWORD*)pIAT = dwPFNAddr;pIAT += 4;pFunAddr+=4;}pImpHdr = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImpHdr + (DWORD)sizeof(IMAGE_IMPORT_DESCRIPTOR));}// 关闭句柄UnmapViewOfFile(lpMapAddr);CloseHandle(hFileMap);CloseHandle(hFile);// 返回地址return &dwOep;
}#endif // 0int main()
{#if 1// 加载PE文件,返回原OEPvoid* pOep = LoadPe();if (pOep != NULL){__asm jmp pOep}#endif // 0return 0;
}
#include <iostream>
#include <Windows.h>
#include <stdio.h>using namespace std;#define FILESIZE  0x00020000         //目标进程的SizeofImage
#define IMAGEBASE 0x01000000char szExeDataBuff[FILESIZE] = {1};
char g_szExeName[] = "winmine.exe";   //要加载的进程路径DWORD g_oep = 0;void LoadPe()
{// 创建文件映射//打开文件HANDLE hFile = CreateFile(g_szExeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE){return ;}// 创建文件映射对象HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);if (hFileMap == NULL){CloseHandle(hFile);return;}//将文件映射进内存LPVOID pView = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);if (pView == NULL){CloseHandle(hFileMap);CloseHandle(hFile);return;}// 修改代码节属性DWORD nOldProtect = 0;VirtualProtect((LPVOID)IMAGEBASE, FILESIZE, PAGE_EXECUTE_READWRITE, &nOldProtect);// 处理PEPIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pView;// 获取pe头大小PIMAGE_NT_HEADERS32 pNt = (PIMAGE_NT_HEADERS32)((DWORD)pView + pDos->e_lfanew);memcpy((void*)IMAGEBASE, (void*)pDos, pNt->OptionalHeader.SizeOfHeaders);// OEPg_oep = pNt->OptionalHeader.AddressOfEntryPoint + IMAGEBASE;// 解析节PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((DWORD) & (pNt->OptionalHeader.Magic) + pNt->FileHeader.SizeOfOptionalHeader);// 节数量unsigned int nNumberOfSections = pNt->FileHeader.NumberOfSections;while (nNumberOfSections != 0){void* pVirtualAddress = (void*)(pSec->VirtualAddress + IMAGEBASE);void* pFileAddress = (void*)(pSec->PointerToRawData + (DWORD)pDos);memcpy(pVirtualAddress, pFileAddress, pSec->SizeOfRawData);nNumberOfSections--;pSec++;}if (pNt->OptionalHeader.NumberOfRvaAndSizes > 2){// 处理导入表PIMAGE_IMPORT_DESCRIPTOR pIm = (PIMAGE_IMPORT_DESCRIPTOR)(pNt->OptionalHeader.DataDirectory[1].VirtualAddress + IMAGEBASE);while (pIm->Name && pIm->FirstThunk){HMODULE hModule = LoadLibraryA((char*)(pIm->Name + IMAGEBASE));if (hModule == NULL){pIm++;continue;}DWORD dwThunkData = pIm->OriginalFirstThunk ? pIm->OriginalFirstThunk : pIm->FirstThunk;if (dwThunkData == 0){return ;}PIMAGE_THUNK_DATA pThunkData = (PIMAGE_THUNK_DATA)(dwThunkData + IMAGEBASE);DWORD* pPfn = (DWORD*)(pIm->FirstThunk + IMAGEBASE);while (pThunkData->u1.AddressOfData){FARPROC farProc = 0;LPCSTR lpParam2 = 0;// 最高位判断if (pThunkData->u1.AddressOfData & 0x80000000){// 序号lpParam2 = LPCSTR(LOWORD(pThunkData->u1.AddressOfData));}else{// 函数名lpParam2 = LPCSTR(pThunkData->u1.AddressOfData + IMAGEBASE + 2);}farProc = GetProcAddress(hModule, lpParam2);// 填充IAT*pPfn = (DWORD)farProc;pThunkData++;pPfn++;}pIm++;}}//取消映射UnmapViewOfFile(pView);//关闭文件映射对象CloseHandle(hFileMap);//关闭文件CloseHandle(hFile);
}int main()
{LoadPe();if (g_oep != 0){__asm{jmp g_oep;}}return 0;
}

思路: 主要难点是代码后移,留出空间

方法1: 内联 汇编 开始 nop

方法2: 把代码放到dll中

方法3: 合并节,全局变量是放在未初始化的节内合并后就会在第一个节

合并节代码:

#include <Windows.h>
#pragma bss_seg (".mySec")
char g_aryImageSize[0x200000];#pragma bss_seg()
#pragma comment(linker,"/MERGE:.mySec=.textbss")const char* g_szExe = "mspaint.exe";int main()
{HANDLE hFile = NULL;HANDLE hFileMap = NULL;LPVOID pFileBuf = NULL;IMAGE_DOS_HEADER* pDosHdr = NULL;IMAGE_NT_HEADERS* pNtHdr = NULL;IMAGE_FILE_HEADER* pFileHdr = NULL;IMAGE_OPTIONAL_HEADER* pOptHdr = NULL;IMAGE_SECTION_HEADER* pSecHdr = NULL;IMAGE_IMPORT_DESCRIPTOR* pImpDes = NULL;DWORD dwSizeOfOptHdr = 0;DWORD dwNumOfSecs = 0;HANDLE hMod = NULL;DWORD  dwSizeOfHeader = 0;DWORD dwOldProc = 0;DWORD dwEntry = 0;HMODULE hDll = NULL;LPDWORD pINT = NULL;LPDWORD pIAT = NULL;DWORD dwAddrOfFunc = 0;IMAGE_IMPORT_DESCRIPTOR zeroImp;memset(&zeroImp, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR));//1、创建文件hMod = GetModuleHandle(NULL);hFile = CreateFile(g_szExe,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hFile == INVALID_HANDLE_VALUE){OutputDebugString("Could not open file.");return -1;}//2、创建文件映射hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);if (hFileMap == NULL){OutputDebugString("Could not create file-mapping object.");return -1;}//3、映射文件内容到内存pFileBuf = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);if (pFileBuf == NULL){OutputDebugString("Could not map view of file.");return -1;}//4、解析DOS头pDosHdr = (IMAGE_DOS_HEADER*)pFileBuf;//5、解析NT头pNtHdr = (IMAGE_NT_HEADERS*)(pDosHdr->e_lfanew + (char*)pFileBuf);//6、解析文件头pFileHdr = &(pNtHdr->FileHeader);//7、解析选项头pOptHdr = &(pNtHdr->OptionalHeader);//8、获取节表个数和选项头大小dwSizeOfOptHdr = pFileHdr->SizeOfOptionalHeader;dwNumOfSecs = pFileHdr->NumberOfSections;//9、解析节表pSecHdr = (IMAGE_SECTION_HEADER*)((char*)pOptHdr + dwSizeOfOptHdr);//10、获取PE头大小和入口点(RVA)dwSizeOfHeader = pOptHdr->SizeOfHeaders;dwEntry = pOptHdr->AddressOfEntryPoint + (DWORD)hMod;//11、获取导入表入口pImpDes = (IMAGE_IMPORT_DESCRIPTOR*)pOptHdr->DataDirectory[1].VirtualAddress;pImpDes = (IMAGE_IMPORT_DESCRIPTOR*)((DWORD)pImpDes + (DWORD)hMod);//12、拷贝PE头VirtualProtect(hMod, dwSizeOfHeader, PAGE_EXECUTE_READWRITE, &dwOldProc);memcpy(hMod, pDosHdr, dwSizeOfHeader);//13、拷贝节数据IMAGE_SECTION_HEADER* pSecTmpHdr = pSecHdr;for (size_t i = 0; i < dwNumOfSecs; i++){LPVOID pSecDataFileOffset = (char*)pFileBuf + pSecTmpHdr->PointerToRawData;LPVOID pSecDataMemory = (LPVOID)((DWORD)hMod + pSecTmpHdr->VirtualAddress);VirtualProtect(pSecDataMemory, pSecTmpHdr->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &dwOldProc);memcpy(pSecDataMemory, pSecDataFileOffset, pSecTmpHdr->SizeOfRawData);pSecTmpHdr = (IMAGE_SECTION_HEADER*)((char*)pSecTmpHdr + sizeof(IMAGE_SECTION_HEADER));}//14、拷贝导入表信息while (true){if (pImpDes->Characteristics == 0 &&pImpDes->FirstThunk == 0 &&pImpDes->Name == 0){break;}if (pImpDes->Name == NULL){break;}LPSTR pDllName = (LPSTR)((DWORD)hMod + pImpDes->Name);hDll = LoadLibrary(pDllName);if (pImpDes->FirstThunk == NULL){break;}//获取导入名称表pINT = (LPDWORD)((DWORD)hMod + pImpDes->OriginalFirstThunk);if (pINT == NULL){pINT = (LPDWORD)((DWORD)hMod + pImpDes->FirstThunk);}//获取导入地址表pIAT = (LPDWORD)((DWORD)hMod + pImpDes->FirstThunk);//while (true){DWORD dwINT = *pINT;if (dwINT == 0){break;}//判断是符号导入还是名称导入LPSTR pApiName = NULL;if (dwINT & 0x80000000){pApiName = (LPSTR)dwINT;pApiName = LPSTR((DWORD)pApiName & 0x0000ffff);}else{pApiName = LPSTR(dwINT + (DWORD)hMod + sizeof(WORD));}*pIAT = (DWORD)GetProcAddress(hDll, pApiName);pINT++;pIAT++;}pImpDes++;}__asm jmp dwEntry;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/76831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QGIS中第三方POI坐标偏移的快速校正-百度POI

1.百度POI&#xff1a; name,lng,lat,address 龙记黄焖鸡米饭(共享区店),121.908315,30.886636,南汇新城镇沪城环路699弄117号(A1区110室) 好福记黄焖鸡(御桥路店),121.571409,31.162292,沪南路2419弄26号1层B间 御品黄焖鸡米饭(安亭店),121.160322,31.305977,安亭镇新源路792号…

SQL的调优方案

一、前言 SQL调优是提升数据库性能的关键手段。需结合索引优化、SQL语句优化、执行计划分析及数据库架构设计等多方面综合处理。 二、索引优化 创建合适索引 高频查询字段&#xff1a;对WHERE、JOIN、ORDER BY涉及的字段创建索引&#xff0c;尤其是区分度高的字段&#xff08…

【项目管理】第一部分 信息技术 1/2

相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 概要 知识点&#xff1a; 现代化基础设施、数字经济、工业互联网、车联网、智能制造、智慧城市、数字政府、5G、常用数据库类型、数据仓库、信息安全、网络安全态势感知、物联网、大数…

【玩泰山派】1、mac上使用串口连接泰山派

文章目录 前言picocom工具连接泰山派安装picocom工具安装ch340的驱动串口工具接线使用picocom连接泰山派 参考 前言 windows上面有xshell这个好用的工具可以使用串口连接板子&#xff0c;在mac上好像没找到太好的工具&#xff0c;只能使用命令行工具去搞了。 之前查找说mac上…

【C++奇遇记】C++中的进阶知识(继承(一))

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 数据库专栏 初阶数据结构 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如…

【Scratch编程系列】Scratch编程软件界面

Scratch是一款由麻省理工学院(MIT&#xff09; 设计开发的少儿编程工具。其特点是&#xff1a;使用者可以不认识英文单词&#xff0c;也可以不使用键盘&#xff0c;就可以进行编程。构成程序的命令和参数通过积木形状的模块来实现。用鼠标拖动指令模块到脚本区就可以了。 这个软…

开篇 - 配置Unlua+VsCode的智能提示、调试以及学习方法

智能提示 为要绑定Lua的蓝图创建模板文件&#xff0c;这会在Content/Script下生成lua文件 然后点击生成智能代码提示&#xff0c;这会在Plugins/Unlua/Intermediate/生成Intenllisense文件夹 打开VSCode,点击文件->将工作区另存为。生成一个空工作区&#xff0c;放置在工程…

QEMU-KVM加SPICE,云电脑诞生了

没错&#xff01;‌QEMU-KVM SPICE‌ 的组合&#xff0c;本质上就是一套‌轻量级云电脑&#xff08;云桌面&#xff09;‌的解决方案。通过虚拟化技术将计算资源池化&#xff0c;再通过SPICE协议提供流畅的远程桌面体验&#xff0c;用户用任意设备&#xff08;笔记本/平板/瘦客…

hashtable遍历的方法有哪些

在 Java 中&#xff0c;遍历 Hashtable&#xff08;或其现代替代品 HashMap&#xff09;有多种方式&#xff0c;以下是 6 种常用方法的详细说明和代码示例&#xff1a; 1. 使用 keySet() 增强 for 循环 Hashtable<String, Integer> table new Hashtable<>(); // …

如何完整迁移 Git 仓库 ?

Git 已经成为软件开发中版本控制和协作的事实上的标准。有时&#xff0c;开发人员可能需要将整个 Git 存储库 (包括其历史记录、分支和标记) 移动到新的位置或托管服务。在这个全面的指南中&#xff0c;我们将讨论在不丢失任何关键数据或历史记录的情况下无缝地重新定位完整 Gi…

BPSK调制器的作用和基本原理

BPSK&#xff08;Binary Phase Shift Keying&#xff0c;二进制相移键控&#xff09;调制器是数字通信系统中的关键组件&#xff0c;其核心作用是将二进制数字信号转换为模拟载波信号&#xff0c;通过相位变化传递信息。其具体作用的详细说明如下&#xff1a; 一、BPSK调制器的…

LeetCode-98. 验证二叉搜索树

一、题目 给定一个二叉树&#xff0c;判断其是否是一个有效的二叉搜索树。假设一个二叉搜索树具有如下特征&#xff1a; 若它的左子树不空&#xff0c;则左子树上所有结点的值均小于它的根结点的值&#xff1b; 若它的右子树不空&#xff0c;则右子树上所有结点的值均大于它的…

Python菜鸟教程(小程序)

目录 一.简易计算器 二.学生成绩分级 三.密码设置 四.作业选择 点赞收藏,评论支持 一.简易计算器 print(-------使用的运算符-------\n) print(1.加号) print(2.减号) print(3.乘号) print(4.除号) Aint(input(请输入第一个数: )) Bint(input(请输入第二个数: )) Fi…

Golang的Goroutine(协程)与runtime

目录 Runtime 包概述 Runtime 包常用函数 1. GOMAXPROCS 2. Caller 和 Callers 3. BlockProfile 和 Stack 理解Golang的Goroutine Goroutine的基本概念 特点&#xff1a; Goroutine的创建与启动 示例代码 解释 Goroutine的调度 Gosched的作用 示例代码 输出 解…

Dubbo(30)如何配置Dubbo的服务分片?

配置Dubbo的服务分片&#xff08;也称为服务分组&#xff09;可以帮助你将不同的服务实例分组&#xff0c;以实现隔离和管理。通过服务分片&#xff0c;可以在同一个注册中心中注册多个相同接口的服务&#xff0c;但它们属于不同的分组&#xff0c;消费者可以根据需要选择特定分…

文档的预解析

1. 预解析的核心目标 浏览器在正式解析&#xff08;Parsing&#xff09;HTML 前&#xff0c;会启动一个轻量级的 预解析器&#xff08;Pre-Parser&#xff09;&#xff0c;快速扫描文档内容&#xff0c;实现&#xff1a; 提前发现并加载关键资源&#xff08;如 CSS、JavaScrip…

通过构造函数和几何条件,研究了不同函数的最近点存在性、性质及单调性

解&#xff1a; &#xff08;1&#xff09;对于函数 f ( x ) 1 x f(x) \frac{1}{x} f(x)x1​ 和点 M ( 1 , 0 ) M(1, 0) M(1,0)&#xff0c;构造函数 s ( x ) ( x − 1 ) 2 ( 1 x ) 2 s(x) (x - 1)^2 \left(\frac{1}{x}\right)^2 s(x)(x−1)2(x1​)2。求导得到 s ′ …

C语言之编译和debug工具

gcc gcc是GUN项目为C和C提供的编译器 入门案例 gcc编译器最简单的使用案例&#xff1a;gcc hello.c -o hello&#xff0c;hello.c是源文件&#xff0c;-o参数指定了结果文件的名称 gcc命令的选项&#xff1a; -v&#xff1a;打印编译细节-E&#xff1a;仅仅进行预处理&…

Altshuller矛盾矩阵查询:基于python和streamlit

基于python和streamlit实现的Altshuller矛盾矩阵查询 import streamlit as st import json# 加载数据 st.cache_resource def load_data():with open(parameter.json, encodingutf-8) as f:parameters json.load(f)with open(way.json, encodingutf-8) as f:contradictions …

Maven的下载配置及在Idea中的配置

编写项目管理中存在的问题 在大型Java项目开发中&#xff0c;依赖管理是一个极其复杂的挑战。传统方式下&#xff0c;开发者需要手动下载并引入数十甚至上百个JAR包到项目中&#xff0c;这一过程不仅繁琐低效&#xff0c;还存在诸多痛点&#xff1a; 依赖传递性问题&#xff1a…