《Windows PE》7.4 资源表应用
本节我们将通过两个示例程序,演示对PE文件内图标资源的置换与提取。
本节必须掌握的知识点:
更改图标
提取图标资源
7.4.1 更改图标
让我们来做一个实验,替换PE文件中现有的图标。如果手工替换,一定是先找到资源表,然后分别替换图标资源和图标组资源就可以了。当然这个过程稍微有点繁复,可能会涉及到其他资源的重定位。还好,Windows操作系统为开发者提供了一组更新PE文件中资源的API函数:BeginUpdateResource、UpdateResource、EndUpdateResource。用来枚举 PE 文件中资源的函数有:EnumResourceTypes、EnumResourceNames、EnumResourceLanguages。具体的使用方法可以参见MSDN,下面我们将使用这些函数实现图标资源的替换。
实验五十:更改图标
●模块1:resource.h(略)
●模块2:peinfo.rc(略)
●模块3:info.h
#pragma once
#ifndef INFO_H_
#define INFO_H_#include <windows.h>
#include <richedit.h> //CHARFORMAT富文本结构定义
#include <commctrl.h> //通用控件
#pragma comment(lib,"comctl32.lib")
#include <strsafe.h> //StringCchCopy
#include <stdlib.h>// 文件中的ICO头部
typedef struct
{byte bWidth; //宽度byte bHeight; //高度byte bColorCount; //颜色数byte bReserved; //保留字,必须为0WORD wPlanes; //调色板WORD wBitCount; //每个像素的位数DWORD dwBytesInRes; //资源长度DWORD dwImageOffset; //资源在文件偏移
}ICON_DIR_ENTRY;typedef struct
{WORD idReserved; //保留字,必须为0WORD idType; //资源类别,如果是1表示为ICO文件WORD idCount; //图标数量//ICON_DIR_ENTRY idEntries; //图标项,一个图标一项
}ICON_DIR;//PE中ICO头部
typedef struct
{byte bWidth; //宽度byte bHeight; //高度byte bColorCount; //颜色数byte bReserved; //保留字,必须为0WORD wPlanes; //调色板WORD wBitCount; //每个像素的位数DWORD dwBytesInRes; //资源长度WORD nID; //资源在文件序号
}PE_ICON_DIR_ENTRY;
typedef struct
{WORD idReserved; //保留字,必须为0WORD idType; //资源类别,如果是1表示为ICO文件WORD idCount; //图标数量PE_ICON_DIR_ENTRY idEntries; //图标项,一个图标一项
}PE_ICON_DIR;//函数声明
BOOL CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Exception(void);
void init(); //初始化
void _OpenFile();//打开PE文件并处理
int CALLBACK _Handler(EXCEPTION_POINTERS * lpExceptionPoint);
void ShowErrMsg();
void _AppendInfo(const TCHAR * _lpsz);//往文本框中追加文本
//将boy.ico图标替换指定PE程序的图标
BOOL _doUpdate(TCHAR* lpszFile, TCHAR* lpszExeFile);#endif
●模块4:PEUpdateIcon.c
/*------------------------------------------------------------------------FileName: PEUpdateIcon.c实验50:更改程序图标实例(支持32位和64位PE文件)(c) bcdaren, 2024
-----------------------------------------------------------------------*/
#include <strsafe.h> //StringCchCopy
#include "resource.h"
#include "info.h"HANDLE hInstance;
HWND hWinMain, hWinEdit;
HMODULE hRichEdit;
TCHAR szFileName[MAX_PATH];
HANDLE hFileDump;
HANDLE hFile;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{TCHAR szDllEdit[] = TEXT("RichEd20.dll");TCHAR szClassEdit[] = TEXT("RichEdit20W");//peinfo.rc中定义hRichEdit = LoadLibrary((LPCWSTR)&szDllEdit);hInstance = GetModuleHandle(NULL);DialogBoxParam(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL,
(DLGPROC)DlgProc, (LPARAM)0);FreeLibrary(hRichEdit);return 0;
}//初始化窗口函数
void init()
{CHARFORMAT stCf;TCHAR szClassEdit[] = TEXT("RichEdit20A");TCHAR szFont[] = TEXT("宋体");HINSTANCE hInstance;hWinEdit = GetDlgItem(hWinMain, IDC_INFO);//为窗口程序设置图标hInstance = GetModuleHandle(NULL);HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ICO_MAIN));//HICON hIcon = LoadIcon(hInstance, TEXT("#111"));SendMessage(hWinMain, WM_SETICON, ICON_BIG, (LPARAM)hIcon);//设置编辑控件SendMessage(hWinEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);RtlZeroMemory(&stCf, sizeof(stCf));stCf.cbSize = sizeof(stCf);stCf.yHeight = 9 * 20;stCf.dwMask = CFM_FACE | CFM_SIZE | CFM_BOLD;StringCchCopy((LPTSTR)&stCf.szFaceName, lstrlen(szFont) + 1, (LPCTSTR)&szFont);SendMessage(hWinEdit, EM_SETCHARFORMAT, 0, (LPARAM)&stCf);SendMessage(hWinEdit, EM_EXLIMITTEXT, 0, -1);//设为-1表示无限制
}//富文本窗口回调函数
BOOL CALLBACK DlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{const TCHAR szErr[] = TEXT("文件格式错误!");const TCHAR szErrFormat[] = TEXT("这个文件不是PE格式的文件!");switch (wMsg){case WM_CLOSE:EndDialog(hWnd, 0);return TRUE;case WM_INITDIALOG:hWinMain = hWnd;init(); //初始化return TRUE;case WM_COMMAND:switch (wParam){case IDM_EXIT:EndDialog(hWnd, 0);return TRUE;case IDM_OPEN:_OpenFile();return TRUE;case IDM_1:MessageBox(NULL, szErrFormat, szErr, MB_ICONWARNING);return TRUE;case IDM_2:MessageBox(NULL, szErrFormat, szErr, MB_ICONWARNING);return TRUE;case IDM_3:MessageBox(NULL, szErrFormat, szErr, MB_ICONWARNING);return TRUE;}}return FALSE;
}//执行比对PE文件
void _OpenFile()
{OPENFILENAME stOF;HANDLE hFile = NULL;HANDLE hMapFile = NULL;PBYTE lpMemory = NULL; //PE文件内存映射文件地址int dwFileSize;const TCHAR szDefaultExt[] = TEXT("exe");const TCHAR szFilter[] = TEXT("PE Files (*.exe)\0*.exe\0")\TEXT("DLL Files(*.dll)\0*.dll\0")\TEXT("SCR Files(*.scr)\0*.scr\0")\TEXT("FON Files(*.fon)\0*.fon\0")\TEXT("DRV Files(*.drv)\0*.drv\0")\TEXT("All Files(*.*)\0*.*\0\0");const TCHAR szErr[] = TEXT("文件格式错误!");const TCHAR szErrFormat[] = TEXT("操作文件时出现错误!");const TCHAR szOut1[] = TEXT("----------------------------------------------------------------\r\n")TEXT("待处理的PE文件:%s\r\n");static TCHAR lpszBoyIcon[] =
TEXT("D:\\code\\winpe\\ch07\\PEUpdateIcon\\boy.ico");const TCHAR szFailure[] = TEXT("执行图标修改失败。");const TCHAR szSuccess[] = TEXT("恭喜你,图标修改成功成功的。");IMAGE_DOS_HEADER *lpstDOS; //DOS块地址IMAGE_NT_HEADERS *lpstNT; //PE文件头地址//显示打开文件对话框RtlZeroMemory(&stOF, sizeof(stOF));stOF.lStructSize = sizeof(stOF);stOF.hwndOwner = hWinMain;stOF.lpstrFilter = szFilter;stOF.lpstrFile = szFileName;stOF.nMaxFile = MAX_PATH;stOF.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;stOF.lpstrDefExt = szDefaultExt;if (!GetOpenFileName(&stOF))return;//打开PE文件hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_WRITE, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);if (hFile == INVALID_HANDLE_VALUE)MessageBox(NULL, TEXT("打开文件失败!"), NULL, MB_ICONWARNING);else{//获取文件大小dwFileSize = GetFileSize(hFile, NULL);//创建内存映射文件if (dwFileSize){if (hMapFile = CreateFileMapping(hFile,
NULL, PAGE_READONLY, 0, 0, NULL)){//获得文件在内存的映象起始位置lpMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);//异常处理方法2:if (!lpMemory){atexit(Exception);goto _ErrFormat;exit(EXIT_FAILURE);}//检查PE文件是否有效lpstDOS = (IMAGE_DOS_HEADER *)lpMemory;if (lpstDOS->e_magic != IMAGE_DOS_SIGNATURE){//如果非PE文件-异常处理atexit(Exception);goto _ErrFormat;exit(EXIT_FAILURE);}lpstNT = (IMAGE_NT_HEADERS *)(lpMemory + lpstDOS->e_lfanew);if (lpstNT->Signature != IMAGE_NT_SIGNATURE){//如果非PE文件-异常处理atexit(Exception);goto _ErrFormat;exit(EXIT_FAILURE);}//将boy.ico的图标数据写入PE文件if (_doUpdate(lpszBoyIcon, szFileName))_AppendInfo(szSuccess);else_AppendInfo(szFailure);goto _ErrorExit;_ErrFormat:MessageBox(hWinMain, szErrFormat, NULL, MB_OK);_ErrorExit:if (lpMemory)UnmapViewOfFile(lpMemory);}if (hMapFile)CloseHandle(hMapFile);}if (hFile)CloseHandle(hFile);}return;
}//RITCH控件添加文本信息--以 null 结尾的字符串
void _AppendInfo(const TCHAR * _lpsz)
{CHARRANGE stCR;//检索文本控件内文本的长度stCR.cpMin = GetWindowTextLength(hWinEdit);stCR.cpMax = stCR.cpMin;//择并替换文本控件的选定内容SendMessage(hWinEdit, EM_EXSETSEL, 0, (LPARAM)&stCR);//EM_REPLACESEL以 null 结尾的字符串的指针替换SendMessage(hWinEdit, EM_REPLACESEL, FALSE, (LPARAM)_lpsz);
}//异常处理
void Exception(void)
{MessageBox(hWinMain, TEXT("获得文件在内存的映象起始位置失败!"), NULL, MB_OK);
}/*
;-----------------------------------
;将boy.ico图标替换指定PE程序的图标
;使用win32 api函数UpdateResource实现此功能
;-----------------------------------
*/
BOOL _doUpdate(TCHAR* lpszFile, TCHAR* lpszExeFile)
{ICON_DIR stID;ICON_DIR_ENTRY stIDE;PE_ICON_DIR stGID;HANDLE hFile, hUpdate;DWORD dwReserved, nSize, nGSize;BOOL flag = FALSE;LPVOID pIcon, pGrpIcon;hFile = CreateFile(lpszFile,GENERIC_READ,0,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL);if (hFile == INVALID_HANDLE_VALUE)return 0;RtlZeroMemory(&stID,sizeof(stID));ReadFile(hFile,&stID,sizeof(stID),&dwReserved,NULL);RtlZeroMemory(&stIDE, sizeof(stIDE));ReadFile(hFile, &stIDE, sizeof(stIDE), &dwReserved, NULL);nSize = stIDE.dwBytesInRes;pIcon = GlobalAlloc(GPTR, nSize);SetFilePointer(hFile, stIDE.dwImageOffset, NULL, FILE_BEGIN);if (!ReadFile(hFile, pIcon, nSize, &dwReserved, NULL))goto _ret;RtlZeroMemory(&stGID,sizeof(stGID));stGID.idCount = stID.idCount;stGID.idReserved = 0;stGID.idType = 1;RtlMoveMemory(&stGID.idEntries,&stIDE,12);stGID.idEntries.nID = 0;nGSize = sizeof(stGID);pGrpIcon = GlobalAlloc(GPTR, nGSize);RtlMoveMemory(pGrpIcon,&stGID,nGSize);//开始修改hUpdate = BeginUpdateResource(lpszExeFile,FALSE); //检索句柄,可使用该句柄在二进制模块中添加,删除或替换资源UpdateResource(hUpdate,RT_GROUP_ICON,(LPCWSTR)1,LANG_CHINESE,pGrpIcon,nGSize);flag = UpdateResource(hUpdate,RT_ICON, (LPCWSTR)1,LANG_CHINESE,pIcon,nSize);EndUpdateResource(hUpdate,FALSE);if (flag == FALSE)MessageBox(NULL, L"替换资源失败!", NULL, MB_OK);elsegoto over;
_ret:GlobalFree(pIcon);CloseHandle(hFile);return flag;
over:CloseHandle(hFile);return flag;
}
运行:
图7-7 替换图标
总结
上述示例选择打开一个PE文件,然后_doUpdate函数实现图标资源的替换。具体实现步骤如下:
1.首先调用CreateFile函数打开boy.ico图标文件。
2.然后调用ReadFile函数,分别将图标文件的头部信息和图标项读取到缓冲区中。
3.接着分配一个和图标资源大小一样的内存空间,并将整个图标文件读取到该内存中。
4.然后再将初始化后的PE_ICON_DIR结构变量stGID复制到一个新分配的内存块中。
5.最后调用一组资源替换的API函数BeginUpdateResource、UpdateResource和EndUpdateResource完成替换。
7.4.2 提取图标资源
一个ICO文件由三大部分组成:第一部分是图标头,第二部分是图标项,第三部分为图标数据。PE资源表中,第一部分和第二部分组合成图标组资源,第三部分的每个图标数据对应一个图标资源。接下来我们给出一个提取图标的示例程序。
实验五十一:提取图标资源
●模块1:resource.h(略)
●模块2:peinfo.rc(略)
●模块3:info.h
#pragma once
#ifndef INFO_H_
#define INFO_H_#include <windows.h>
#include <richedit.h> //CHARFORMAT富文本结构定义
#include <commctrl.h> //通用控件
#pragma comment(lib,"comctl32.lib")
#include <strsafe.h> //StringCchCopy
#include <stdlib.h>//函数声明
BOOL CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//void Exception(void);
void init(); //初始化
void _OpenFile();//打开PE文件并处理
DWORD RVAToOffset(IMAGE_DOS_HEADER * lpFileHead, DWORD dwRVA);// 将内存偏移量RVA转换为文件偏移
DWORD GetRVASection(IMAGE_DOS_HEADER * lpFileHead, DWORD dwRVA);//查找 RVA 所在的节区
int CALLBACK _Handler(EXCEPTION_POINTERS * lpExceptionPoint);
//void ShowErrMsg();
void _AppendInfo(const TCHAR * _lpsz);//往文本框中追加文本
//PE文件处理模块
void _getResource(PBYTE, IMAGE_NT_HEADERS *, int);//获取PE文件的资源信息
void ProcessRes(PBYTE lpFile, PBYTE lpRes, IMAGE_RESOURCE_DIRECTORY * lpResDir, DWORD dwLevel);
void _getIcoData(PBYTE lpFile, PBYTE lpRes, DWORD number, DWORD off, DWORD size);//处理单个ICO文件
int _getFinnalData(PBYTE lpFile, PBYTE lpRes, DWORD number);//将图标数据写入文件
#endif
●模块4:RvaToFileOffset.c(略)
●模块5:PEDumpIcon.c
/*------------------------------------------------------------------------FileName:PEDumpIcon.c实验51:提取程序图标实例(支持32位和64位PE文件)(c) bcdaren, 2024
-----------------------------------------------------------------------*/
#include <strsafe.h> //StringCchCopy
#include "resource.h"
#include "info.h"HANDLE hInstance;
HWND hWinMain, hWinEdit;
HMODULE hRichEdit;
TCHAR szFileName[MAX_PATH];
HANDLE hFileDump;
HANDLE hFile;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{TCHAR szDllEdit[] = TEXT("RichEd20.dll");TCHAR szClassEdit[] = TEXT("RichEdit20W");//peinfo.rc中定义hRichEdit = LoadLibrary((LPCWSTR)&szDllEdit);hInstance = GetModuleHandle(NULL);DialogBoxParam(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DlgProc, (LPARAM)0);FreeLibrary(hRichEdit);return 0;
}//初始化窗口函数
void init()
{CHARFORMAT stCf;TCHAR szClassEdit[] = TEXT("RichEdit20A");TCHAR szFont[] = TEXT("宋体");HINSTANCE hInstance;hWinEdit = GetDlgItem(hWinMain, IDC_INFO);//为窗口程序设置图标hInstance = GetModuleHandle(NULL);HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ICO_MAIN));//HICON hIcon = LoadIcon(hInstance, TEXT("#111"));SendMessage(hWinMain, WM_SETICON, ICON_BIG, (LPARAM)hIcon);//设置编辑控件SendMessage(hWinEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);RtlZeroMemory(&stCf, sizeof(stCf));stCf.cbSize = sizeof(stCf);stCf.yHeight = 9 * 20;stCf.dwMask = CFM_FACE | CFM_SIZE | CFM_BOLD;StringCchCopy((LPTSTR)&stCf.szFaceName, lstrlen(szFont) + 1, (LPCTSTR)&szFont);SendMessage(hWinEdit, EM_SETCHARFORMAT, 0, (LPARAM)&stCf);SendMessage(hWinEdit, EM_EXLIMITTEXT, 0, -1);//设为-1表示无限制
}//富文本窗口回调函数
BOOL CALLBACK DlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{const TCHAR szErr[] = TEXT("文件格式错误!");const TCHAR szErrFormat[] = TEXT("这个文件不是PE格式的文件!");switch (wMsg){case WM_CLOSE:EndDialog(hWnd, 0);return TRUE;case WM_INITDIALOG:hWinMain = hWnd;init(); //初始化return TRUE;case WM_COMMAND:switch (wParam){case IDM_EXIT:EndDialog(hWnd, 0);return TRUE;case IDM_OPEN:_OpenFile();return TRUE;case IDM_1:MessageBox(NULL, szErrFormat, szErr, MB_ICONWARNING);return TRUE;case IDM_2:MessageBox(NULL, szErrFormat, szErr, MB_ICONWARNING);return TRUE;case IDM_3:MessageBox(NULL, szErrFormat, szErr, MB_ICONWARNING);return TRUE;}}return FALSE;
}//执行比对PE文件
void _OpenFile()
{OPENFILENAME stOF;HANDLE hFile = NULL;HANDLE hMapFile = NULL;PBYTE lpMemory = NULL; //PE文件内存映射文件地址int dwFileSize;const TCHAR szDefaultExt[] = TEXT("exe");const TCHAR szFilter[] = TEXT("PE Files (*.exe)\0*.exe\0")\TEXT("DLL Files(*.dll)\0*.dll\0")\TEXT("SCR Files(*.scr)\0*.scr\0")\TEXT("FON Files(*.fon)\0*.fon\0")\TEXT("DRV Files(*.drv)\0*.drv\0")\TEXT("All Files(*.*)\0*.*\0\0");const TCHAR szErr[] = TEXT("文件格式错误!");const TCHAR szErrFormat[] = TEXT("操作文件时出现错误!");const TCHAR szOut1[] = TEXT("----------------------------------------------------------------\r\n")TEXT("待处理的PE文件:%s\r\n");static TCHAR szBuffer[256];IMAGE_DOS_HEADER *lpstDOS; //DOS块地址IMAGE_NT_HEADERS *lpstNT; //PE文件头地址//显示打开文件对话框RtlZeroMemory(&stOF, sizeof(stOF));stOF.lStructSize = sizeof(stOF);stOF.hwndOwner = hWinMain;stOF.lpstrFilter = szFilter;stOF.lpstrFile = szFileName;stOF.nMaxFile = MAX_PATH;stOF.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;stOF.lpstrDefExt = szDefaultExt;if (!GetOpenFileName(&stOF))return;//打开PE文件hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);if (hFile == INVALID_HANDLE_VALUE)MessageBox(NULL, TEXT("打开文件失败!"), NULL, MB_ICONWARNING);else{//获取文件大小dwFileSize = GetFileSize(hFile, NULL);//创建内存映射文件if (dwFileSize){if (hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)){//获得文件在内存的映象起始位置lpMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);//异常处理方法2:if (!lpMemory){MessageBox(hWinMain, szErrFormat, NULL, MB_OK);}//检查PE文件是否有效lpstDOS = (IMAGE_DOS_HEADER *)lpMemory;if (lpstDOS->e_magic != IMAGE_DOS_SIGNATURE){//如果非PE文件-异常处理MessageBox(hWinMain, szErrFormat, NULL, MB_OK);}lpstNT = (IMAGE_NT_HEADERS *)(lpMemory + lpstDOS->e_lfanew);if (lpstNT->Signature != IMAGE_NT_SIGNATURE){MessageBox(hWinMain, szErrFormat, NULL, MB_OK);}//到此为止,该文件的验证已经完成。为PE结构文件wsprintf(szBuffer, szOut1, szFileName);_AppendInfo(szBuffer);//显示资源信息_getResource(lpMemory, lpstNT, dwFileSize);if (lpMemory)UnmapViewOfFile(lpMemory);}if (hMapFile)CloseHandle(hMapFile);}if (hFile)CloseHandle(hFile);}return;
}//RITCH控件添加文本信息--以 null 结尾的字符串
void _AppendInfo(const TCHAR * _lpsz)
{CHARRANGE stCR;//检索文本控件内文本的长度stCR.cpMin = GetWindowTextLength(hWinEdit);stCR.cpMax = stCR.cpMin;//择并替换文本控件的选定内容SendMessage(hWinEdit, EM_EXSETSEL, 0, (LPARAM)&stCR);//EM_REPLACESEL以 null 结尾的字符串的指针替换SendMessage(hWinEdit, EM_REPLACESEL, FALSE, (LPARAM)_lpsz);
}
●模块6:GetResource.c
/*
;遍历资源表项的图标组资源
;_lpFile:文件地址
;_lpRes:资源表地址
*/
#include <windows.h>
#include "info.h"extern TCHAR szFileName[MAX_PATH]; //pemian.c模块中定义
extern HANDLE hWinEdit,hFileDump;
extern HWND hWinMain;void _AppendInfo(const TCHAR * _lpsz);
DWORD RVAToOffset(IMAGE_DOS_HEADER * lpFileHead, DWORD dwRVA);
DWORD GetRVASection(IMAGE_DOS_HEADER * lpFileHead, DWORD dwRVA);//遍历资源表项的图标组资源:参数1:PE文件地址;参数2:资源块起始地址;
void ProcessRes(PBYTE lpFile, PBYTE lpRes, IMAGE_RESOURCE_DIRECTORY * lpResDir, DWORD dwLevel)
{const TCHAR szOut10[] = TEXT("资源表中有图标组%d个。\r\n")TEXT("----------------------------------------------------------------\r\n\r\n");const TCHAR szLevel3[] = TEXT("图标组%4d所在文件位置:0x%08x 资源长度:%d\r\n");const TCHAR szNoIconArray[] = TEXT("资源表中没有发现图标组!");static TCHAR szBuffer[1024];static TCHAR szResName[256];IMAGE_RESOURCE_DIRECTORY * lpstRES_DIR;//资源目录IMAGE_RESOURCE_DIRECTORY_ENTRY * lpstRES_DIR_ENT;//目录项IMAGE_RESOURCE_DATA_ENTRY * lpstRES_DATA_ENT;int number; //资源数量DWORD dwNextLevel;DWORD lpAddr, lpAddr2;DWORD IDname, dwTemp1, dwTemp2, dwTemp3;DWORD dwICO = 0 ; //ICO文件的个数dwNextLevel = dwLevel + 1;//检查资源目录表,得到资源目录项的数量lpstRES_DIR = lpResDir;number = lpstRES_DIR->NumberOfIdEntries + lpstRES_DIR->NumberOfNamedEntries;
//IMAGE_RESOURCE_DIRECTORY结构后面紧跟着是IMAGE_RESOURCE_DIRECTORY_ENTRY结构lpstRES_DIR_ENT = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)((PBYTE)lpstRES_DIR + sizeof(IMAGE_RESOURCE_DIRECTORY));//循环处理每个资源目录项while (number--){RtlZeroMemory(szBuffer, sizeof(szBuffer));//OffsetToData字段最高位为1,后七位指向下层目录块的起始地址IMAGE_RESOURCE_DIRECTORY结构lpAddr = lpstRES_DIR_ENT->OffsetToData;if (lpAddr & 0x80000000){lpAddr &= 0x7fffffff;lpAddr += (DWORD)lpRes;//第一层:资源类型IDname = lpstRES_DIR_ENT->Name;//目录项名称字符串或ID//最高位为1时,低7位值作为指向UNICODE编码的资源名IAMGE_RESOURCE_STRING_U结构//如果是按名称定义的资源类型,跳过 if (IDname & 0x80000000){goto _next;}//高位为0时,表示字段的值作为ID使用else{if (IDname == 0x0e) //判断编号是否为图标组{//移动到第二级目录//计算目录项的个数lpstRES_DIR = (IMAGE_RESOURCE_DIRECTORY*)lpAddr;dwICO = lpstRES_DIR->NumberOfNamedEntries +
lpstRES_DIR->NumberOfIdEntries;wsprintf(szBuffer, szOut10, dwICO);_AppendInfo(szBuffer);//跳过第二级目录头定位到第二级目录项lpAddr2 = lpAddr + sizeof(IMAGE_RESOURCE_DIRECTORY);dwTemp1 = 0;while (dwICO--){lpstRES_DIR_ENT =
(IMAGE_RESOURCE_DIRECTORY_ENTRY*)lpAddr2;//直接访问到数据,获取数据在文件的偏移及大小dwTemp1++;lpAddr = lpstRES_DIR_ENT->OffsetToData;if (lpAddr & 0x80000000){lpAddr &= 0x7fffffff; //最高位为1lpAddr += (DWORD)lpRes; //第三级lpstRES_DIR = (IMAGE_RESOURCE_DIRECTORY*)lpAddr;//移动到第三级目录,假设目录项数量都为1lpAddr += sizeof(IMAGE_RESOURCE_DIRECTORY);lpstRES_DIR_ENT =
(IMAGE_RESOURCE_DIRECTORY_ENTRY*)lpAddr;//地址指向数据项lpAddr = lpstRES_DIR_ENT->OffsetToData +
(DWORD)lpRes;lpstRES_DATA_ENT =
(IMAGE_RESOURCE_DATA_ENTRY*)lpAddr;dwTemp3 = lpstRES_DATA_ENT->Size;dwTemp2 = RVAToOffset((IMAGE_DOS_HEADER *)lpFile,
lpstRES_DATA_ENT->OffsetToData);wsprintf(szBuffer, szLevel3, dwTemp1, dwTemp2,dwTemp3);_AppendInfo(szBuffer);//处理单个ICO文件,参数1:文件开始,参数2:资源表开始//参数3:PE ICO头开始,参数4:编号,参数5:PE ICO头大小_getIcoData(lpFile, lpRes, dwTemp1, dwTemp2,
dwTemp3);}lpAddr2 += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY);}goto _next;}elsegoto _next;}}_next:lpstRES_DIR_ENT++;}if (dwICO == 0)_AppendInfo(szNoIconArray);
}
//获取PE文件的资源信息
void _getResource(PBYTE lpFile, IMAGE_NT_HEADERS * _lpPeHead, int _dwSize)
{const TCHAR szNoResource[] = TEXT("\r\n未发现资源表!");static TCHAR szBuffer[256];static TCHAR szSectionName[16];static TCHAR szNameB[256];static TCHAR szNameW[256];IMAGE_NT_HEADERS32 * lpstNT32; //PE32文件头IMAGE_NT_HEADERS64 * lpstNT64; //PE64文件头IMAGE_RESOURCE_DIRECTORY * lpstRES_DIR;//资源目录DWORD rva, address;lpstNT32 = _lpPeHead;lpstNT64 = (IMAGE_NT_HEADERS64 *)_lpPeHead;//检测是否存在资源--数据目录第2项if (lpstNT64->OptionalHeader.Magic == 0x020B) //64位PE文件{//数据目录项的第3项rva = lpstNT64->OptionalHeader.DataDirectory[2].VirtualAddress; }elserva = lpstNT32->OptionalHeader.DataDirectory[2].VirtualAddress;if (!rva){_AppendInfo(szNoResource);return;}//求资源表在文件的偏移address = RVAToOffset((IMAGE_DOS_HEADER *)lpFile, rva);if (!address)return;
//资源目录的实际地址lpstRES_DIR = (IMAGE_RESOURCE_DIRECTORY *)(address + (DWORD)lpFile); /*显示所有资源目录块的信息; 传入的两个参数分别表示; 1、文件头位置; 2、资源表位置*/ProcessRes(lpFile, (PBYTE)lpstRES_DIR, lpstRES_DIR, 1);
}
●模块7:GetIconData.c
/*
;通过PE ICO头获取ICO数据
;参数1:文件开始
;参数2:资源表开始
;参数3:PE ICO头开始
;参数4:编号(由此构造磁盘文件名g12.ico)
;参数5:PE ICO头大小
*/
#include <windows.h>
#include "info.h"extern TCHAR szFileName[MAX_PATH]; //pemian.c模块中定义
extern HANDLE hFile;
extern HWND hWinMain;// 文件中的ICO头部
typedef struct
{byte bWidth ; //宽度byte bHeight ; //高度byte bColorCount ; //颜色数byte bReserved ; //保留字,必须为0WORD wPlanes ; //调色板WORD wBitCount ; //每个像素的位数DWORD dwBytesInRes ; //资源长度DWORD dwImageOffset ; //资源在文件偏移
}ICON_DIR_ENTRY;//PE中ICO头部
typedef struct
{byte bWidth; //宽度byte bHeight; //高度byte bColorCount; //颜色数byte bReserved; //保留字,必须为0WORD wPlanes; //调色板WORD wBitCount; //每个像素的位数DWORD dwBytesInRes; //资源长度WORD dwImageOffset; //资源在文件偏移
}PE_ICON_DIR_ENTRY;//处理单个ICO文件
void _getIcoData(PBYTE lpFile, PBYTE lpRes, DWORD number, DWORD off, DWORD size)
{const TCHAR szFile[] = TEXT(" >>新建文件%s\r\n");const TCHAR szOut11[] = TEXT("g%d.ico");const TCHAR szOut13[] = TEXT(" >>图标组%4d中共有图标:%d个。\r\n");const TCHAR szICOHeader[] = TEXT(" >> 完成ICO头部信息 \r\n");TCHAR szFileName1[MAX_PATH];static TCHAR szBuffer[256];DWORD dwTemp, dwCount, dwTemp1;DWORD dwForward,lpMemory;DWORD dwIcoDataSize; //图标数据的大小PE_ICON_DIR_ENTRY * lpPE_ICON_DIR_ENTRY;ICON_DIR_ENTRY lpIconDE;//PE_ICON_DIR_ENTRY lpPEIconDE;WORD order;DWORD lpAddr;wsprintf(szFileName1,szOut11,number);wsprintf(szBuffer,szFile,szFileName1);_AppendInfo(szBuffer);//将内存写入文件以供检查hFile = CreateFile(szFileName1,GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);//定位文件指针lpMemory = (DWORD)lpFile + off;//写入6个字节文件头WriteFile(hFile, (PBYTE)lpMemory, 6, &dwTemp, NULL);//求出图标组包含图标的个数dwCount = *(PWORD)((PBYTE)lpMemory + 4);wsprintf(szBuffer,szOut13,number,dwCount);_AppendInfo(szBuffer);//求第一个图标数据在文件中的偏移dwForward = dwCount * 2 + size;//每一个记录多2个字节//定位到ICO图标项起始lpPE_ICON_DIR_ENTRY = (PE_ICON_DIR_ENTRY *)((PBYTE)lpMemory + 6);dwIcoDataSize = 0;dwTemp1 = dwCount;while (dwTemp1--){//将PE_ICON_DIR_ENTRY结构中的大部分字段赋值,除最后一个字段外lpIconDE.bWidth = lpPE_ICON_DIR_ENTRY->bWidth;lpIconDE.bHeight = lpPE_ICON_DIR_ENTRY->bHeight;lpIconDE.bColorCount = lpPE_ICON_DIR_ENTRY->bColorCount;lpIconDE.bReserved = lpPE_ICON_DIR_ENTRY->bReserved;lpIconDE.wPlanes = lpPE_ICON_DIR_ENTRY->wPlanes;lpIconDE.wBitCount = lpPE_ICON_DIR_ENTRY->wBitCount;lpIconDE.dwBytesInRes = lpPE_ICON_DIR_ENTRY->dwBytesInRes;//该值需要修正,记录图标数据在文件偏移。//第一个图标的该值是文件ICO头大小//以后的图标的该值是上一个加上数据长度lpIconDE.dwImageOffset = dwForward + dwIcoDataSize;WriteFile(hFile, &lpIconDE, sizeof(ICON_DIR_ENTRY),&dwTemp,NULL);//为下一次计算地址做准备dwIcoDataSize = lpPE_ICON_DIR_ENTRY->dwBytesInRes;lpPE_ICON_DIR_ENTRY++;}//该循环结束,所有的头部信息已经完毕_AppendInfo(szICOHeader);//开始下一个循环,将所有图标数据写入文件lpAddr = (DWORD)lpMemory + 6;dwTemp1 = dwCount;while (dwTemp1--){lpPE_ICON_DIR_ENTRY = (PE_ICON_DIR_ENTRY *)lpAddr;//写入文件图标数据order = lpPE_ICON_DIR_ENTRY->dwImageOffset;//取得图标的顺号//返回eax为图标数据大小_getFinnalData(lpFile, lpRes, order);//lpAddr += sizeof(PE_ICON_DIR_ENTRY);//16个字节--错误lpAddr += 14;}CloseHandle(hFile);
}
//将图标数据写入文件
/*
;参数:lpFile 文件内存起始地址
;参数: lpRes 资源表起始地址
;参数:nubmer为图标顺号
*/
int _getFinnalData(PBYTE lpFile, PBYTE lpRes, DWORD number)
{static TCHAR szBuffer[1024];static TCHAR szResName[256];DWORD lpMem, dwTemp,dwTemp1, dwTemp2, dwTemp3;DWORD dwICO = 0; //ICO文件的个数int count = 0; //图标数据大小int counter; //资源数量DWORD lpAddr, IDname;IMAGE_RESOURCE_DIRECTORY * lpstRES_DIR;//资源目录IMAGE_RESOURCE_DIRECTORY_ENTRY * lpstRES_DIR_ENT;//目录项IMAGE_RESOURCE_DATA_ENTRY * lpstRES_DATA_ENT;const TCHAR szLevel31[] = TEXT(" >> 图标%4d所在文件位置:0x%08x 资源长度:%d\r\n");const TCHAR szFinished[] = TEXT(" >> 完成写入。\r\n\r\n");const TCHAR szNoIconArray[] = TEXT("资源表中没有发现图标组!");//计算目录项的个数lpstRES_DIR = (IMAGE_RESOURCE_DIRECTORY *)lpRes;counter = lpstRES_DIR->NumberOfIdEntries + lpstRES_DIR->NumberOfNamedEntries;
//IMAGE_RESOURCE_DIRECTORY结构后面紧跟着是IMAGE_RESOURCE_DIRECTORY_ENTRY结构lpstRES_DIR_ENT = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)((PBYTE)lpstRES_DIR + sizeof(IMAGE_RESOURCE_DIRECTORY));//循环处理每个资源目录项while (counter--){RtlZeroMemory(szBuffer, sizeof(szBuffer));
//OffsetToData字段最高位为1,后七位指向下层目录块的起始地址IMAGE_RESOURCE_DIRECTORY结构lpAddr = lpstRES_DIR_ENT->OffsetToData;if (lpAddr & 0x80000000){lpAddr &= 0x7fffffff;lpAddr += (DWORD)lpRes;//第一层:资源类型IDname = lpstRES_DIR_ENT->Name;//目录项名称字符串或ID
//最高位为1时,低7位值作为指向UNICODE编码的资源名IAMGE_RESOURCE_STRING_U结构//如果是按名称定义的资源类型,跳过 if (IDname & 0x80000000){goto _next;}//高位为0时,表示按编号定义的资源类型else{//第一层指向了资源类别if (IDname == 0x03) //判断编号是否为图标组{//移动到第二级目录//计算目录项的个数lpstRES_DIR = (IMAGE_RESOURCE_DIRECTORY*)lpAddr;dwICO = lpstRES_DIR->NumberOfNamedEntries +
lpstRES_DIR->NumberOfIdEntries;//跳过第二级目录头定位到第二级目录项lpAddr += sizeof(IMAGE_RESOURCE_DIRECTORY);lpstRES_DIR_ENT = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)lpAddr;dwTemp1 = 0;while (dwICO--){//直接访问到数据,获取数据在文件的偏移及大小dwTemp1++;//判断序号是否和指定的一致if (dwTemp1 != number)goto _loop;//如果一致,则继续查找数据lpAddr = lpstRES_DIR_ENT->OffsetToData;if (lpAddr & 0x80000000){lpAddr &= 0x7fffffff; //最高位为1lpAddr += (DWORD)lpRes; //第三级lpstRES_DIR = (IMAGE_RESOURCE_DIRECTORY*)lpAddr;//移动到第三级目录,假设目录项数量都为1lpAddr += sizeof(IMAGE_RESOURCE_DIRECTORY);lpstRES_DIR_ENT =
(IMAGE_RESOURCE_DIRECTORY_ENTRY*)lpAddr;//地址指向数据项lpAddr = lpstRES_DIR_ENT->OffsetToData +
(DWORD)lpRes;lpstRES_DATA_ENT =
(IMAGE_RESOURCE_DATA_ENTRY*)lpAddr;dwTemp3 = lpstRES_DATA_ENT->Size;dwTemp2 = RVAToOffset((IMAGE_DOS_HEADER *)lpFile,lpstRES_DATA_ENT->OffsetToData);wsprintf(szBuffer, szLevel31, dwTemp1, dwTemp2,
dwTemp3);_AppendInfo(szBuffer);//将dwTemp2开始的dwTemp3个字节写入文件lpMem = (DWORD)lpFile + dwTemp2;WriteFile(hFile, (PBYTE)lpMem, dwTemp3, &dwTemp,
NULL);_AppendInfo(szFinished);count = 1;return count;}_loop:lpstRES_DIR_ENT++;}goto _next;}elsegoto _next;}}_next:lpstRES_DIR_ENT++;}if (dwICO == 0)_AppendInfo(szNoIconArray);return count;
}
运行:
图7-8 提取图标
总结
上述程序假设图标是由多个图标数据组成,即资源表中一定存在图标组。
ICO头部分+ICO项描述在资源图标组里定义,每一部分数据则在资源图标里定义。程序 首先检测是否存在图标组资源,如果不存在则退出;如果存在,就定位到图标组资源数据,通过将字段编号(1个字)修改为偏移(2个字),重新组合ICO头部使其符合ICO文件头部要求。最后,分別读取各部分图标资源数据,顺序连接到ICO头部后即可。
相关文章:
《Windows PE》7.4 资源表应用
本节我们将通过两个示例程序,演示对PE文件内图标资源的置换与提取。 本节必须掌握的知识点: 更改图标 提取图标资源 7.4.1 更改图标 让我们来做一个实验,替换PE文件中现有的图标。如果手工替换,一定是先找到资源表,…...
【重生之我要苦学C语言】猜数字游戏和关机程序的整合
今天来把学过的猜数字游戏和关机程序来整合一下 如果有不明白的可以看往期的博客 废话不多说,上代码: #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <time.h> #include <stdlib.h> #include <string.h> void…...
基于centos7脚本一键部署gpmall商城
基于centos7脚本一键部署单节点gpmall商城,该商城可单节点,可集群,可高可用集群部署,VMware17,虚拟机IP:192.168.200.100 将软件包解压到/root目录 [rootlocalhost ~]# ls dist …...
Mac book英特尔系列?M系列?两者有什么区别呢
众所周知,Mac book有M系列,搭载的是苹果自研的M芯片,也有着英特尔系列,搭载的是英特尔的处理器,虽然从 2020 年开始,苹果公司逐步推出了自家研发的 M 系列芯片,并逐渐将 MacBook 产品线过渡到 M…...
Python unstructured库详解:partition_pdf函数完整参数深度解析
Python unstructured库详解:partition_pdf函数完整参数深度解析 1. 简介2. 基础文件处理参数2.1 文件输入参数2.2 页面处理参数 3. 文档解析策略3.1 strategy参数详解3.2 策略选择建议 4. 表格处理参数4.1 表格结构推断 5. 语言处理参数5.1 语言设置 6. 图像处理参数…...
<项目代码>YOLOv8路面病害识别<目标检测>
YOLOv8是一种单阶段(one-stage)检测算法,它将目标检测问题转化为一个回归问题,能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法(如Faster R-CNN),YOLOv8具有更高的…...
广告牌和标签学习
效果: 知识学习: entities添加标签label和广告牌billboard label: text:文本添加 font:字体大小和字体类型 fillColor:字体颜色 outlineColor:字体外轮廓颜色 outlineWidth:字体外轮…...
GDB 从裸奔到穿戴整齐
无数次被问道:你在终端下怎么调试更高效?或者怎么在 Vim 里调试?好吧,今天统一回答下,我从来不在 vim 里调试,因为它还不成熟。那除了命令行 GDB 裸奔以外,终端下还有没有更高效的方法ÿ…...
WPF的触发器(Trigger)
WPF(Windows Presentation Foundation)是微软.NET框架的一部分,用于构建Windows客户端应用程序。在WPF中,触发器(Triggers)是一种强大的功能,允许开发者根据控件的状态或属性值来动态改变控件的…...
全能大模型GPT-4o体验和接入教程
GPT-4o体验和接入教程 前言一、原生API二、Python LangchainSpring AI总结 前言 Open AI发布了产品GPT-4o,o表示"omni",全能的意思。 GPT-4o可以实时对音频、视觉和文本进行推理,响应时间平均为 320 毫秒,和人类之间对…...
详解Apache版本、新功能和技术前景
文章目录 一、 版本溯源二、新功能和特性举例1. 模块化和可扩展性增强2. 多处理模块(MPMs)3. 异步支持4. 更细粒度的日志级别控制5. 通用表达式解析器6. HTTP/2支持7. Server Push8. Early Hints9. 更好的SSL/TLS支持10. 更安全的默认设置 三、 技术前景…...
Docker Redis集群3主3从模式
主从集群 docker run -d --name redis-node1 --net host --privilegedtrue -v /home/redis/node1:/data redis:7.0 --cluster-enabled yes --appendonly yes --port 9371docker run -d --name redis-node2 --net host --privilegedtrue -v /home/redis/node2:/data redis:7.0 …...
【Go语言】
type关键字的用法 定义结构体定义接口定义类型别名类型定义类型判断 别名实际上是为了更好地理解代码/ 这里要分点进行记录 使用传值的例子,当两个类型不一样需要进行类型转换 type Myint int // 自定义类型,基于已有的类型自定义一个类型type Myin…...
【Spring Boot】元注解
元注解 1.元注解1.1 Target1.2 Retention1.3 Inherited1.4 Documented1.5 interface 2.自定义注解2.1 创建自定义注解类2.2 实现业务逻辑2.3 使用自定义注解 1.元注解 元注解就是定义注解的注解,是 Java 提供的用于定义注解的基本注解。 注解 说明 Retention是注解…...
基于信号分解和多种深度学习结合的上证指数预测模型
大家好,我是带我去滑雪! 为了给投资者提供更准确的投资建议、帮助政府和监管部门更好地制定相关政策,维护市场稳定,本文对股民情绪和上证指数之间的关系进行更深入的研究,并结合信号分解、优化算法和深度学习对上证指数…...
基于Spring Boot的酒店住宿管理平台
1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理酒店客房管理系统的相关信息成为必然。开发…...
游聚对战平台 三国战纪2012CE修改器修改地址
游聚对战平台 三国战纪2012比较全的一次地址。 工具 ce修改器 自行百度下载 1袖箭 2褐色鸡蛋 3毒堂 4飞盘 5火焰弹 6绿色鸡蛋 7金珠 8毒蝎 9毒镖 10铁莲花 11张陵剑 12张角巾 13太清丹经 14黄石公 15九节杖 16隐身衣 17神仙笔 18 玉蜂术(效果不明)19天师…...
Qt Creator中的项目栏
shadow build: [基础]Qt Creator 的 Shadow build(影子构建)-CSDN博客 影子构建:将源码路径和构建路径分开(生成的makefile文件和其他产物都不放到源码路径),以此来保证源码路径的清洁。 实验1: 我创建了两个项目:…...
keepalived+web 实现双机热备
环境:利用keeplived实现web服务器的双机热备(高可用) 注意: (1) 利用keeplivedweb做双击热备(高可用),最少需要两台服务器,可以实现多域名对应一个VIP,并且访问不同域名,显示不同主页…...
关于python的import
在Python中,import语句用于导入其他模块或模块中的特定部分,以便在代码中使用它们。这就可以重用代码,而不是每次都从头开始编写所有的功能。 基本用法 导入整个模块: import module_name 例如: import math print(…...
帕金森后期吞咽困难:破解难题,重拾生活美味!
在这个快节奏的时代,健康成为了我们最宝贵的财富。然而,对于帕金森病患者及其家庭而言,随着病情的进展,尤其是进入后期阶段,吞咽困难成为了他们不得不面对的严峻挑战。今天,就让我们一起走进这个温暖而坚韧…...
android 添加USB网卡并配置DNS
工作需要,需要使用TBox分享的网络,Android将TBox当作一个USB网卡,接下来就简单了,配置这个网卡的信息即可。 加载默认网卡的信息在frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java中 Ethern…...
【面试经典150】day 8
#1024程序员节 | 征文# 作为一个未来的程序员,现在我要继续刷题了。 力扣时刻。 目录 1.接雨水 2.罗马数字转整数 3.最后一个单词的长度 4.最长公共前缀 5.反转字符串中的单词 1.接雨水 好好好好好好,一开始就接雨水。我记得接了n次了。。。 痛苦战…...
Python -- 网络爬虫
Python – 网络爬虫 流程: 1. 连接链接获取页面内容(html文件); 2. 过滤获取需要信息(正则) [可能重复步骤1,2] ; 3. 存储文件到本地。一)网络连接获取页面内容 # 网络…...
【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-5
文件下载与邀请翻译者 学习英特尔开发手册,最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册,会是一件耗时费力的工作。如果有愿意和我一起来做这件事的,那么ÿ…...
设计模式4 适配器 (adapter)
一句话,适配器按照客户的需求, 适配当前已有的接口。 目标接口:reqeust() public interface Target {void request(); //this is client needed interface }已有接口:specificRequest package com.example.adapter;import android.uti…...
《分布式机器学习模式》:解锁分布式ML的实战宝典
在大数据和人工智能时代,机器学习已经成为推动技术进步的重要引擎。然而,随着数据量的爆炸性增长和模型复杂度的提升,单机环境下的机器学习已经难以满足实际需求。因此,将机器学习应用迁移到分布式系统上,成为了一个不…...
【项目实战】HuggingFace初步实战,使用HF做一些小型任务
Huggingface初步实战 一、前期准备工作二、学习pipline2.1.试运行代码,使用HuggingFace下载模型2.2. 例子1,情感检测分析(只有积极和消极两个状态)2.3. 例子2,文本生成 三、学会使用Tokenizer & Model3.1.tokenizer(分词器&am…...
堆的应用——堆排序和TOP-K问题
1.堆排序 想法⼀: 基于已有数组建堆、取堆顶元素完成排序。也就是利用写好的堆数据结构(之前的文章有讲解),去实现排序。 void HeapSort(int* a, int n){HP hp;for(int i 0; i < n; i){HPPush(&hp,a[i]);}int i 0;whi…...
探秘 MySQL 数据类型的艺术:性能与存储的精妙平衡
文章目录 前言🎀一、数据类型分类🎀二、整数类型(举例 TINYINT 和 INT )🎫2.1 TINYINT 和 INT 类型的定义2.1.1 TINYINT2.1.2 INT 🎫2.2 表的操作示例2.2.1 创建包含 TINYINT 和 INT 类型的表2.2.2 插入数据…...
divi wordpress/重庆今天刚刚发生的重大新闻
购买商品房没拿到合同,购房者可以向开发商索要合同,购房合同是购房的凭证,开发商有权提供购房合同给购房者。如果开发商迟迟不给合同,购房者要保留购房证据积极维权。关于购买商品房没拿到合同要如何处理的问题,东营律…...
沈阳网站制作费用/北京做seo的公司
可以从在存储帐户中存储为托管磁盘或非托管磁盘的通用 VM 中创建托管映像资源。 然后可以使用该映像创建多个 VM。 使用 Sysprep 通用化 Windows VM Sysprep 将删除所有个人帐户信息及其他某些数据,并准备好要用作映像的计算机。 有关 Sysprep 的详细信息࿰…...
seo于刷网站点击/近两年网络营销成功案例
List是一个接口,不能调用对象,它是Colllection的子接口,Collection中的方法也在List中适用 我们一般创建的List对象指向ArrayList或者LinkList的子对象,秉承多态(downcasting)向下转型的原则 常用方法介绍 package …...
网站制作的设计思路/外贸网
有没有必要考这个问题没有具体说法,因为每个人的需求、观点以及目的都会不同,这则是导致个人有没有必要考取PMP证书的因素。 毕竟,如果我在这放肆吹PMP是一定要考的,而且不看个人需求,那么如果你需求中不需要PMP&…...
做游戏直播什么游戏视频网站好/百度权重怎么看
try catch finally 执行顺序 仅仅在下面4中情况下不会执行finally语句 : ①.如果在try 或catch语句中执行了System.exit(0)。 ②.在执行finally之前jvm崩溃了。 ③.try语句中执行死循环。 ④.电源断电。 1,无论try或catch,return几,fina…...
网站建设公司需要具备什么/本地推广最有效的方法
输入一个字母实现大小写转换,若输入不为字母重复出入,直到输入为字母为止,并实现大小写转换。 要求使用模运算。 我看了小甲鱼之后写的 注意此处模运算对象为二进制。 A的ASCII码为65,转换为二进制为1000001 Z的ASCII码为90&#…...