/* * Rufus: The Reliable USB Formatting Utility * Extract icon from executable and set autorun.inf * Copyright © 2012-2024 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */ #ifdef _CRTDBG_MAP_ALLOC #include #include #endif #include #include #include #include #include "rufus.h" #include "missing.h" #include "resource.h" #include "msapi_utf8.h" #pragma pack(push) #pragma pack(2) typedef struct { BYTE bWidth; // Width, in pixels, of the image BYTE bHeight; // Height, in pixels, of the image BYTE bColorCount; // Number of colors in image (0 if >=8bpp) BYTE bReserved; // Reserved ( must be 0) WORD wPlanes; // Color Planes WORD wBitCount; // Bits per pixel DWORD dwBytesInRes; // How many bytes in this resource? DWORD dwImageOffset; // Where in the file is this image? } ICONDIRENTRY, *LPICONDIRENTRY; typedef struct { WORD idReserved; // Reserved (must be 0) WORD idType; // Resource Type (1 for icons) WORD idCount; // How many images? ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em) } ICONDIR, *LPICONDIR; typedef struct { BITMAPINFOHEADER icHeader; // DIB header RGBQUAD icColors[1]; // Color table BYTE icXOR[1]; // DIB bits for XOR mask BYTE icAND[1]; // DIB bits for AND mask } ICONIMAGE, *LPICONIMAGE; typedef struct { BYTE bWidth; // Width, in pixels, of the image BYTE bHeight; // Height, in pixels, of the image BYTE bColorCount; // Number of colors in image (0 if >=8bpp) BYTE bReserved; // Reserved WORD wPlanes; // Color Planes WORD wBitCount; // Bits per pixel DWORD dwBytesInRes; // how many bytes in this resource? WORD nID; // the ID } GRPICONDIRENTRY, *LPGRPICONDIRENTRY; typedef struct { WORD idReserved; // Reserved (must be 0) WORD idType; // Resource type (1 for icons) WORD idCount; // How many images? GRPICONDIRENTRY idEntries[1]; // The entries for each image } GRPICONDIR, *LPGRPICONDIR; #pragma pack(pop) /* * Extract the main icon set from the exe */ BOOL ExtractAppIcon(const char* path, BOOL bSilent) { HGLOBAL res_handle; HRSRC res; WORD i; BYTE* res_data; DWORD res_size, offset; HANDLE hFile = INVALID_HANDLE_VALUE; BOOL r = FALSE; GRPICONDIR* icondir; icondir = (GRPICONDIR*)GetResource(hMainInstance, MAKEINTRESOURCEA(IDI_ICON), _RT_GROUP_ICON, "icon", &res_size, FALSE); assert(icondir != NULL && icondir->idCount <= 64); if (icondir == NULL || icondir->idCount > 64) goto out; hFile = CreateFileU(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { uprintf("Unable to create icon '%s': %s.", path, WindowsErrorString()); goto out; } // Write .ico header if (!WriteFileWithRetry(hFile, icondir, 3 * sizeof(WORD), NULL, WRITE_RETRIES)) { uprintf("Could not write icon header: %s.", WindowsErrorString()); goto out; } // Write icon data offset = 3 * sizeof(WORD) + icondir->idCount * sizeof(ICONDIRENTRY); for (i = 0; i < icondir->idCount; i++) { // Write the common part of ICONDIRENTRY if (!WriteFileWithRetry(hFile, &icondir->idEntries[i], sizeof(GRPICONDIRENTRY)-sizeof(WORD), NULL, WRITE_RETRIES)) { uprintf("Could not write ICONDIRENTRY[%d]: %s.", i, WindowsErrorString()); goto out; } res = FindResourceA(hMainInstance, MAKEINTRESOURCEA(icondir->idEntries[i].nID), _RT_ICON); // Write the DWORD offset if (!WriteFileWithRetry(hFile, &offset, sizeof(offset), NULL, WRITE_RETRIES)) { uprintf("Could not write ICONDIRENTRY[%d] offset: %s.", i, WindowsErrorString()); goto out; } offset += SizeofResource(NULL, res); } for (i = 0; i < icondir->idCount; i++) { // Write icon data res = FindResourceA(hMainInstance, MAKEINTRESOURCEA(icondir->idEntries[i].nID), _RT_ICON); res_handle = LoadResource(NULL, res); res_data = (BYTE*)LockResource(res_handle); res_size = SizeofResource(NULL, res); if (!WriteFileWithRetry(hFile, res_data, res_size, NULL, WRITE_RETRIES)) { uprintf("Could not write icon data #%d: %s.", i, WindowsErrorString()); goto out; } } suprintf("Created: %s", path); r = TRUE; out: safe_closehandle(hFile); return r; } /* * Create an autorun.inf, if none exists * We use this to set the icon as well as labels that are longer than 11/32 chars or, * in the case of FAT, contain non-English characters */ BOOL SetAutorun(const char* path) { FILE* fd; char filename[64]; wchar_t wlabel[128], wRufusVersion[32]; static_sprintf(filename, "%sautorun.inf", path); fd = fopen(filename, "r"); // If there's an existing autorun, don't overwrite if (fd != NULL) { uprintf("%s already exists - keeping it", filename); fclose(fd); return FALSE; } // No "/autorun.inf" => create a new one in UTF-16 LE mode fd = fopen(filename, "w, ccs=UTF-16LE"); if (fd == NULL) { uprintf("Unable to create %s", filename); uprintf("NOTE: This may be caused by a poorly designed security solution. See https://goo.gl/QTobxX."); return FALSE; } GetWindowTextW(hLabel, wlabel, ARRAYSIZE(wlabel)); GetWindowTextW(hMainDialog, wRufusVersion, ARRAYSIZE(wRufusVersion)); // coverity[invalid_type] fwprintf_s(fd, L"; Created by %s\n; " LTEXT(RUFUS_URL) L"\n", wRufusVersion); // coverity[invalid_type] fwprintf_s(fd, L"[autorun]\nicon = autorun.ico\nlabel = %s\n", wlabel); fclose(fd); uprintf("Created: %s", filename); // .inf -> .ico assert(strlen(filename) >= 2); filename[strlen(filename) - 1] = 'o'; filename[strlen(filename) - 2] = 'c'; return ExtractAppIcon(filename, FALSE); }