当前位置: 首页 > news >正文

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;
}

相关文章:

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

https://bpsend.net/thread-316-1-1.html LoadPE - pe 加载器 壳的前身 如果想访问一个程序运行起来的内存,一种方法就是跨进程读写内存,但是跨进程读写内存需要来回调用api,不如直接访问地址来得方便,那么如果我们需要直接访问地址,该怎么做呢?.需要把dll注进程,注进去的代码…...

【Redis】通用命令

使用者通过redis-cli客户端和redis服务器交互&#xff0c;涉及到很多的redis命令&#xff0c;redis的命令非常多&#xff0c;我们需要多练习常用的命令&#xff0c;以及学会使用redis的文档。 一、get和set命令&#xff08;最核心的命令&#xff09; Redis中最核心的两个命令&…...

Android学习总结之service篇

引言 在 Android 开发里&#xff0c;Service 与 IntentService 是非常关键的组件&#xff0c;它们能够让应用在后台开展长时间运行的操作。不过&#xff0c;很多开发者仅仅停留在使用这两个组件的层面&#xff0c;对其内部的源码实现了解甚少。本文将深入剖析 Service 和 Inte…...

基于CATIA产品结构树智能排序的二次开发技术解析——深度定制BOM层级管理系统的Pycatia实践

引言 在航空制造与汽车装配领域&#xff0c;CATIA产品结构树&#xff08;Product Tree&#xff09;的规范性直接影响MBOM管理效率。传统手动排序存在两大痛点&#xff1a; ​多级编号混乱&#xff1a;混合零件号&#xff08;PartNumber&#xff09;与实例名&#xff08;Insta…...

机器人轨迹跟踪控制——CLF-CBF-QP

本次使用MATLAB复现CLF-CBF-QP算法,以实现机器人轨迹跟踪同时保证安全性能 模型 使用自行车模型来进行模拟机器人的移动动态,具体的模型推导参考车辆运动学模型-自行车模型 采用偏差变量 p ~ = p − p r e f u ~ = u − u r e f \tilde{p} = p - p_{ref} \\ \tilde{u} = …...

道路裂缝数据集CrackForest-156-labelme

来源于开源的数据集 https://github.com/cuilimeng/CrackForest-dataset 进行整理修改而成。 文章目录 1. 介绍2. 数据文件3. 应用场景4. 相关工具5. 下载地址 1. 介绍 在现代城市管理中&#xff0c;道路状况的监测与维护是确保交通安全和城市基础设施健康的重要环节。 CrackF…...

数据定义语言

一、DDL的核心功能 DDL用于定义和管理数据库对象的结构,包括数据库、表、索引、视图等,主要操作包括创建、修改、删除。其核心命令包括: CREATE:创建对象(数据库、表、索引等) ALTER:修改对象结构(如添加/删除列) DROP:删除对象 TRUNCATE:清空表数据(保留结构) RE…...

爬楼梯问题-动态规划

一、题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 方法1. 1 阶 1 阶 方法2. 2 阶…...

MySQL篇(四)事务相关知识详解

MySQL篇(四&#xff09;事务相关知识详解 MySQL篇(四&#xff09;事务相关知识详解一、事务的特性&#xff08;ACID&#xff09;原子性&#xff08;Atomicity&#xff09;一致性&#xff08;Consistency&#xff09;隔离性&#xff08;Isolation&#xff09;持久性&#xff08;…...

C++第14届蓝桥杯b组学习笔记

1. 日期统计 小蓝现在有一个长度为 100100 的数组&#xff0c;数组中的每个元素的值都在 00 到 99 的范围之内。数组中的元素从左至右如下所示&#xff1a; 5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2 7 0 5 8 8 5 7 0 9 9 1 9 4 4…...

4.5蓝桥杯|高塔登顶方案(5025)

作者语录&#xff1a; 1、 从不会做到会做的过程&#xff0c;从不理解到不理解的过程&#xff0c;从一个不会做这道题的人的角度出发看这个问题&#xff0c;好命苦嗷嗷嗷&#xff01; 2、只有我受煎熬吗&#xff0c;偶买噶&#xff0c;&#xff0c;&#xff0c; 目录 研究步骤…...

[MySQL初阶]MySQL(9)事务机制

标题&#xff1a;[MySQL初阶]MySQL&#xff08;9&#xff09;事物机制 水墨不写bug 文章目录 一、认识事务1、多线程访问数据库出现的问题2、对CURD的限制是通过事务机制实现的3、事务的四个属性4、哪些引擎支持事务 二、事务的提交与autocommit设置三、事务的隔离性和隔离级别…...

3535 数组分割

3535 数组分割 ⭐️难度&#xff1a;困难 &#x1f31f;考点&#xff1a;2023、省赛、动态规划 &#x1f4d6; &#x1f4da; import java.util.*;public class Main {static int MOD 1000000007;static int N 1005;public static void main(String[] args) {Scanner sc …...

线程池的工作原理

固定线程池&#xff1a;线程池中的线程数是固定的&#xff0c;线程池创建时就已经设定了固定的线程数量。在任务提交时&#xff0c;线程池会将任务分配给空闲的线程执行。如果所有线程都在执行任务&#xff0c;新的任务会被放到任务队列中&#xff0c;直到有线程空闲出来。 线…...

论文导读 | SOSP23 | Gemini:大模型 内存CheckPoint 快速故障恢复

本期分享的是一篇SOSP 2023论文&#xff1a; Gemini: Fast Failure Recovery in Distributed Training with In-Memory Checkpoints Zhuang Wang (Rice University), Zhen Jia (Amazon Web Services, Inc.), Shuai Zheng (Amazon Web Services), Zhen Zhang (Amazon Web Servic…...

windows 常用命令总结

工作中用到的 Linux 总结&#xff08;持续更新中...&#xff09;_linux工作经验-CSDN博客 PS&#xff1a; 推荐使用 powershell 而不是 cmd&#xff0c;因为PowerShell 是一个更先进和功能更强大的工具&#xff08; powershell 有命令记忆功能&#xff0c;比较方便&#xff09…...

【Linux】进程间通信、匿名管道、进程池

一.什么是通信 进程间通信(Inter-Process Communication&#xff0c;IPC),是指在操作系统中&#xff0c;不同进程之间进行数据交换和同步的机制。由于每个进程通常拥有独立的内存空间&#xff0c;进程间无法直接访问对方的内存&#xff0c;因此需要通过特定的机制来实现通信和…...

【Block总结】PlainUSR的局部注意力,即插即用|ACCV2024

论文信息 标题: PlainUSR: Chasing Faster ConvNet for Efficient Super-Resolution作者: Yan Wang, Yusen Li, Gang Wang, Xiaoguang Liu发表时间: 2024年会议/期刊: 亚洲计算机视觉会议&#xff08;ACCV 2024&#xff09;研究背景: 超分辨率&#xff08;Super-Resolution, S…...

35信号和槽_信号槽小结

Qt 信号槽 1.信号槽是啥~~ 尤其是和 Linux 中的信号进行了对比&#xff08;三要素&#xff09; 1) 信号源 2) 信号的类型 3)信号的处理方式 2.信号槽 使用 connect 3.如何查阅文档. 一个控件&#xff0c;内置了哪些信号&#xff0c;信号都是何时触发 一…...

现代复古电影海报品牌徽标设计衬线英文字体安装包 Thick – Retro Vintage Cinematic Font

Thick 是一种大胆的复古字体&#xff0c;专为有影响力的标题和怀旧的视觉效果而设计。其厚实的字体、复古魅力和电影风格使其成为电影海报、产品标签、活动品牌和编辑设计的理想选择。无论您是在引导电影的黄金时代&#xff0c;还是在现代布局中注入复古活力&#xff0c;Thick …...

低代码开发平台:飞帆画 echarts 柱状图

https://fvi.cn/711 柱状图这个控件是由折线图的控件改过来的&#xff0c;在配置中&#xff0c;单选框选择柱状图就行了。...

Linux中C++ gdb调试命令

编译可执行文件需要带上-g选项参数 输入回车则重复执行上一次命令&#xff1b; 进入gdb&#xff1a; gdb 程序名运行gdb命令&#xff1a; r打断点命令&#xff1a; b 行号查看断点命令&#xff1a; i b打印变量命令&#xff1a; p 变量名持续查看变量命令&#xff1a; d…...

Python精进系列:从 __name__ 开始了解 python 常见内置变量

目录 引言一、__name__是什么&#xff1f;案例1&#xff1a;直接运行模块案例2&#xff1a;模块被导入 二、__name__的主要用途&#xff08;一&#xff09;区分主程序和导入模块案例3&#xff1a;测试代码隔离&#xff08;二&#xff09;动态导入模块案例4&#xff1a;根据环境…...

Nacos 服务发现的核心模型有哪些?Service, Instance, Cluster 之间的关系是什么?

Nacos 服务发现的核心模型 Nacos 服务发现的核心数据模型主要围绕以下几个关键概念构建&#xff0c;它们共同构成了服务注册与发现的基础&#xff1a; Namespace (命名空间): 用途: 用于进行环境隔离。比如&#xff0c;你可以为开发环境 (dev)、测试环境 (test) 和生产环境 (p…...

Java程序设计第1章:概述

一、Hello World 1.代码&#xff1a; public class HelloWorld {public static void main(String[] args){System.out.println("Hello World!");} } 2.运行结果&#xff1a; Hello World! 二、输出姓名、学号、班级 1.题目&#xff1a; 编写一个Application&a…...

C++开发工具全景指南

专业编译与调试工具深度解析 2025年4月 编译器套件 GNU Compiler Collection (GCC) GNU编译器套件是自由软件基金会开发的跨平台编译器系统&#xff0c;支持C、C、Objective-C、Fortran、Ada等多种编程语言。作为Linux系统的标准编译器&#xff0c;GCC以其强大的优化能力和…...

Java的Selenium的特殊元素操作与定位之iframe切换

iframe切换 四种切换方式: driver.switchTo().frame(index);driver.switchTo().frame(id);driver.switchTo().frame(name);driver.switchTo().frame(WebElement); 切换之后&#xff0c;回到默认内容页面(否则会找不到元素 driver.switchTo().defaultContent(); //iframe处…...

AI比人脑更强,因为被植入思维模型【42】思维投影思维模型

giszz的理解&#xff1a;本质和外在。我们的行为举止&#xff0c;都是我们的内心的表现。从外边可以看内心&#xff0c;从内心可以判断外在。曾国藩有&#xff17;个识人的方法&#xff0c;大部分的人在他的面前如同没穿衣服一样。对于我们自身的启迪&#xff0c;我认为有四点&…...

7-12 最长对称子串(PTA)

对给定的字符串&#xff0c;本题要求你输出最长对称子串的长度。例如&#xff0c;给定Is PAT&TAP symmetric?&#xff0c;最长对称子串为s PAT&TAP s&#xff0c;于是你应该输出11。 输入格式&#xff1a; 输入在一行中给出长度不超过1000的非空字符串。 输出格式&…...

嵌入式AI的本地化部署的好处

嵌入式AI本地化处理&#xff08;即边缘计算&#xff09;的核心优势在于将AI算力下沉至设备端&#xff0c;直接处理数据而非依赖云端&#xff0c;这种模式在多个维度上展现出显著价值&#xff1a; 一、数据隐私与安全性提升 1. 敏感数据本地存储 金融、医疗等涉及隐私的行业…...

0基础 | 硬件 | 电源系统 一

降压电路LDO 几乎所有LDO都是基于此拓扑结构 图 拓扑结构 LDO属于线性电源&#xff0c;通过控制开关管的导通程度实现稳压&#xff0c;输出纹波小&#xff0c;无开关噪声 线性电源&#xff0c;IoutIin&#xff0c;发热功率P电压差△U*电流I&#xff0c;转换效率Vo/Vi LDO不适…...

LeetCode详解之如何一步步优化到最佳解法:20. 有效的括号

LeetCode详解系列的总目录&#xff08;持续更新中&#xff09;&#xff1a; LeetCode详解之如何一步步优化到最佳解法&#xff1a;前100题目录&#xff08;更新中...&#xff09;-CSDN博客 LeetCode详解系列的上一题链接&#xff1a; LeetCode详解之如何一步步优化到最佳解法…...

LeetCode18四数之和

代码来源&#xff1a;代码随想录 /*** Return an array of arrays of size *returnSize.* The sizes of the arrays are returned as *returnColumnSizes array.* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().*/ int com…...

《K230 从熟悉到...》无线网络

《K230 从熟悉到...》无线网络 STA模式 《庐山派 K230 从熟悉到...》无线网络 无线网络中通常是STA&#xff08;Station&#xff0c;站点&#xff09;和AP&#xff08;Access Point&#xff0c;无线接入点&#xff09;。 STA&#xff08;站点&#xff09; 定义&#xff1a;STA…...

去中心化指数(链上ETF)

去中心化指数&#xff08;链上ETF&#xff09; 核心概念 去中心化指数&#xff1a; 类似传统金融的ETF&#xff08;交易所交易基金&#xff09;&#xff0c;通过一篮子代币分散投资风险&#xff0c;无需主动管理。 核心价值&#xff1a;降低研究成本、分散风险、自动化资产…...

LeeCode题库第1695题

项目场景&#xff1a; 给你一个正整数数组 nums &#xff0c;请你从中删除一个含有 若干不同元素 的子数组。删除子数组的 得分 就是子数组各元素之 和 。 返回 只删除一个 子数组可获得的 最大得分 。 如果数组 b 是数组 a 的一个连续子序列&#xff0c;即如果它等于 a[l],…...

【LeetCode 热题100】23:合并 K 个升序链表(详细解析)(Go语言版)

&#x1f680; LeetCode 热题 23&#xff1a;合并 K 个升序链表&#xff08;详细解析&#xff09; &#x1f4cc; 题目描述 LeetCode 23. Merge k Sorted Lists 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合…...

LeetCode hot 100—删除链表的倒数第N个节点

题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[]示例 3&…...

超级科学软件实验室(中国) : Super Scientific Software Laboratory (SSSLab)

Super Scientific Software Laboratory (SSSLab) gitee 官网...

2025大唐杯仿真1——车联网

车联网 V2N是指车辆与网络 Uu接口是用户设备&#xff08;UE&#xff09;与基站之间的通信接口&#xff0c;用于终端和基站之间的通信 Uu接口可用的是N41频段&#xff0c;归属中国移动 车辆间交互是V2V&#xff0c;频段是PCS PC5接口是一种用于设备间直接通信&#xff08;D2D…...

云资源合规基线:确保云环境安全与合规的完整指南

1. 引言 随着越来越多的企业将其IT基础设施迁移到云端,确保云资源的安全性和合规性变得至关重要。云资源合规基线是一套最佳实践和标准,旨在帮助组织维护安全、高效且符合法规要求的云环境。本文将深入探讨云资源合规基线的各个方面,为IT管理者和安全专业人士提供全面的指导。…...

1.0 软件测试全流程解析:从计划到总结的完整指南

软件测试全流程解析&#xff1a;从计划到总结的完整指南 摘要 本文档详细介绍了软件测试的完整流程&#xff0c;包括测试计划、测试设计、测试执行、测试报告和测试总结等主要阶段。每个阶段都从目标、主要工作、输出物和注意事项等方面进行了详细说明。通过本文档&#xff0…...

@reduxjs/toolkit 报错,解决

项目场景&#xff1a; 使用redux存储状态&#xff0c;写一个reducer 问题描述 报错&#xff1a;Uncaught Error: A case reducer on a non-draftable value must not return undefined import { createSlice } from "reduxjs/toolkit"; //错误写法 const counterS…...

C++蓝桥杯实训篇(二)

片头 嗨咯~小伙伴们&#xff01;今天我们来一起学习算法和贪心思维&#xff0c;准备好了吗&#xff1f;咱们开始咯&#xff01; 第1题 数位排序 对于这道题&#xff0c;我们需要自己写一个排序算法&#xff0c;也就是自定义排序&#xff0c;按照数位从小到大进行排序。 举一…...

YY forget password

YY forget password 老早以前的语音工具&#xff0c;游戏团队协作工具...

Kafka 如何解决消息堆积问题?

Kafka 的消息堆积问题是实际生产中经常遇到的情况&#xff0c;尤其在高并发、大流量、消费者故障或处理速度慢的情况下&#xff0c;非常容易出现。 下面我从诊断 解决方案 实战技巧三步帮你梳理清楚&#xff1a; &#x1f50d; 一、先判断&#xff1a;是否真的“堆积”&…...

如何通过优化HMI设计大幅提升产品竞争力?

一、HMI设计的重要性与竞争力提升 HMI&#xff08;人机交互界面&#xff09;设计在现代产品开发中扮演着至关重要的角色。良好的HMI设计不仅能够提升用户体验&#xff0c;还能显著增强产品的竞争力。在功能趋同的市场环境中&#xff0c;用户体验成为产品竞争的关键。HMI设计通…...

2025大唐杯仿真4——信令流程

Preamble请求...

MyBatis Plus 在 ZKmall开源商城持久层的优化实践

ZKmall开源商城作为基于 Spring Cloud 的高性能电商平台&#xff0c;其持久层通过 MyBatis Plus 实现了多项深度优化&#xff0c;涵盖分库分表、缓存策略、分页性能、多租户隔离等核心场景。以下是具体实践总结&#xff1a; 一、分库分表与插件集成优化 1. 分库分表策略 ​Sh…...

Qt多线程从基础到性能优化

一、为什么需要多线程开发 现代应用程序的性能需求 CPU多核架构的有效利用 复杂任务的解耦与响应式界面保持 二、Qt线程创建四大方式 1. 继承QThread重写run() class WorkerThread : public QThread {void run() override {// 耗时操作qDebug() << "Thread ID…...