Генератор сміттєвих іконок.
Переглядаючи семпли різної малварі, іноді доводиться бачити файли з абсолютно нехитрою іконкою - піксельний рандом з прозорими областями. Таке часто використовується у файлах призначених для прогрузу, просто й ефектно. На черговому файлі, захотілося подібне реалізувати, що і було зроблено. Заодно стала зрозумілою структура * .ico.
Отже:
icogen.h
#ifndef ICOGEN_H
#define ICOGEN_H
#include <windows.h>
#define SystemFunction036 NTAPI SystemFunction036
#include <NTSecAPI.h>
#undef SystemFunction036
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct _ICONDIRENTRY {
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
DWORD dwImageOffset;
} ICONDIRENTRY, *PICONDIRENTRY;
typedef struct _ICONDIR {
WORD idReserved;
WORD idType;
WORD idCount;
PICONDIRENTRY idEntries;
} ICONDIR, *PICONDIR;
typedef struct _ICONIMAGE {
BITMAPINFOHEADER icHeader;
RGBQUAD *icColors;
BYTE *icMask;
} ICONIMAGE, *PICONIMAGE;
typedef struct _ICON {
FILE *hFile;
ICONDIR IconDir;
PICONIMAGE pIconImage;
} ICON, *PICON;
/*
szFileName - файл иконки
aIcoSize - массив с требуемыми размерами иконок (min - 1x1, max - 256x256)
uIcoCount - кол-во элементов (иконок) в массиве
uIcoColor - кол-во используемых цветов
bTransp - прозрачность (от 0 до 255)
return: 0 - успех; -1 - ошибка
*/
int WINAPI icogen_create_ico(const char *szFileName, const uint32_t aIcoSize[], const size_t uIcoCount, const uint32_t uIcoColor, const uint8_t bTransp);
#endif
icogen.c
#include "icogen.h"
ULONG icogen_rnd(const uint32_t uMin, const uint32_t uMax)
{
ULONG lRnd;
return RtlGenRandom(&lRnd, sizeof(ULONG)) ? (uMin <= uMax ? lRnd % (uMax - uMin + 1) + uMin : -1) : -1;
}
int icogen_size_is_ok(const uint32_t aIcoSize[], const size_t uIcoCount) {
for (size_t i = 0; i < uIcoCount; i++) {
if (aIcoSize[i] < 1 || aIcoSize[i] > 256)
return -1;
}
return 0;
}
#define get_mask_size(bit) (((bit)+31)/32*4*(bit))
PICON icogen_init(const char *szFileName, const uint32_t aIcoSize[], const size_t uIcoCount, const uint32_t uIcoColor)
{
if (!icogen_size_is_ok(aIcoSize, uIcoCount) && uIcoCount >= 1 && uIcoColor >= 1) {
PICON pIcon = NULL;
if (pIcon = calloc(1, sizeof(ICON))) {
if (pIcon->hFile = fopen(szFileName, "wb")) {
if (pIcon->IconDir.idEntries = calloc(uIcoCount, sizeof(ICONDIRENTRY))) {
if (pIcon->pIconImage = calloc(uIcoCount, sizeof(ICONIMAGE))) {
for (size_t i = 0; i < uIcoCount; i++) {
if (!(pIcon->pIconImage[i].icColors = calloc(aIcoSize[i] * aIcoSize[i], sizeof(RGBQUAD))))
return NULL;
if (!(pIcon->pIconImage[i].icMask = calloc(1, get_mask_size(aIcoSize[i]))))
return NULL;
}
return pIcon;
}
}
}
}
}
return NULL;
}
void icogen_clear(PICON pIcon, const size_t uIcoCount)
{
for (size_t i = 0; i < uIcoCount; i++) {
if (pIcon->pIconImage[i].icMask)
free(pIcon->pIconImage[i].icMask);
if (pIcon->pIconImage[i].icColors)
free(pIcon->pIconImage[i].icColors);
}
if (pIcon->pIconImage)
free(pIcon->pIconImage);
if (pIcon->IconDir.idEntries)
free(pIcon->IconDir.idEntries);
fclose(pIcon->hFile);
if (pIcon)
free(pIcon);
}
void icogen_write(PICON pIcon, const uint32_t aIcoSize[], const size_t uIcoCount)
{
// icondir
fwrite(&pIcon->IconDir.idReserved, sizeof(pIcon->IconDir.idReserved), 1, pIcon->hFile);
fwrite(&pIcon->IconDir.idType, sizeof(pIcon->IconDir.idType), 1, pIcon->hFile);
fwrite(&pIcon->IconDir.idCount, sizeof(pIcon->IconDir.idCount), 1, pIcon->hFile);
fwrite(pIcon->IconDir.idEntries, sizeof(ICONDIRENTRY), uIcoCount, pIcon->hFile);
for (size_t i = 0; i < uIcoCount; i++) {
// header
fwrite(&pIcon->pIconImage[i].icHeader, sizeof(pIcon->pIconImage[i].icHeader), 1, pIcon->hFile);
// rgb
fwrite(pIcon->pIconImage[i].icColors, sizeof(RGBQUAD), aIcoSize[i] * aIcoSize[i], pIcon->hFile);
// mask
fwrite(pIcon->pIconImage[i].icMask, get_mask_size(aIcoSize[i]), 1, pIcon->hFile);
}
}
int WINAPI icogen_create_ico(const char *szFileName, const uint32_t aIcoSize[], const size_t uIcoCount, const uint32_t uIcoColor, const uint8_t bTransp)
{
PICON pIcon = NULL;
if (pIcon = icogen_init(szFileName, aIcoSize, uIcoCount, uIcoColor)) {
DWORD dwImageOffsetPrev = uIcoCount * sizeof(ICONDIRENTRY) + sizeof(WORD) * 3;
pIcon->IconDir.idReserved = 0;
pIcon->IconDir.idType = 1;
pIcon->IconDir.idCount = (WORD)uIcoCount;
for (size_t i = 0; i < uIcoCount; i++) {
pIcon->IconDir.idEntries[i].bWidth = aIcoSize[i];
pIcon->IconDir.idEntries[i].bHeight = aIcoSize[i];
pIcon->IconDir.idEntries[i].bColorCount = 0;
pIcon->IconDir.idEntries[i].bReserved = 0;
pIcon->IconDir.idEntries[i].wPlanes = 1;
pIcon->IconDir.idEntries[i].wBitCount = 32;
pIcon->IconDir.idEntries[i].dwBytesInRes = sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * aIcoSize[i] * aIcoSize[i]) + get_mask_size(aIcoSize[i]);
pIcon->IconDir.idEntries[i].dwImageOffset = dwImageOffsetPrev;
pIcon->pIconImage[i].icHeader.biSize = sizeof(BITMAPINFOHEADER);
pIcon->pIconImage[i].icHeader.biWidth = aIcoSize[i];
pIcon->pIconImage[i].icHeader.biHeight = 2 * aIcoSize[i];
pIcon->pIconImage[i].icHeader.biPlanes = 1;
pIcon->pIconImage[i].icHeader.biBitCount = 32;
pIcon->pIconImage[i].icHeader.biCompression = 0;
pIcon->pIconImage[i].icHeader.biSizeImage = 0;
pIcon->pIconImage[i].icHeader.biXPelsPerMeter = 0;
pIcon->pIconImage[i].icHeader.biYPelsPerMeter = 0;
pIcon->pIconImage[i].icHeader.biClrUsed = 0;
pIcon->pIconImage[i].icHeader.biClrImportant = 0;
RGBQUAD *rgb = calloc(uIcoColor, sizeof(RGBQUAD));
memset(rgb, bTransp, uIcoColor * sizeof(RGBQUAD));
uint32_t jmp = 0;
for (size_t j = 0; j < aIcoSize[i] * aIcoSize[i]; j++) {
if (!(j % (aIcoSize[i] * aIcoSize[i] / icogen_rnd(1, aIcoSize[i])))) {
for (size_t k = 0; k < uIcoColor; k++) {
RtlGenRandom(rgb + k, 3);
}
jmp = jmp ? 0 : 1;
}
if (icogen_rnd(jmp, 1)) {
pIcon->pIconImage[i].icColors[j] = rgb[icogen_rnd(0, uIcoColor - 1)];
}
}
if (rgb)
free(rgb);
RtlGenRandom(pIcon->pIconImage[i].icMask, get_mask_size(aIcoSize[i]));
dwImageOffsetPrev += pIcon->IconDir.idEntries[i].dwBytesInRes;
}
icogen_write(pIcon, aIcoSize, uIcoCount);
icogen_clear(pIcon, uIcoCount);
return 0;
}
return -1;
}
main.c
#include "icogen.h"
int main(int argc, char **argv)
{
const uint32_t ico[] = { 16, 24, 32, 48, 128, 256 };
if (!icogen_create_ico("icon.ico", ico, sizeof(ico) / sizeof(ico[0]), 2, 255)) {
printf("Successfully completed!\n");
} else {
printf("Error!\n");
}
return 0;
}
Використання на fasm:
format pe console 5.01
section '.text' import readable executable
include 'win32a.inc'
library icogen_dll, 'icogen_dll.dll',\
kernel32, 'kernel32.dll',\
msvcrt, 'msvcrt.dll'
import icogen_dll,\
icogen_create_ico, 'icogen_create_ico'
import kernel32,\
ExitProcess, 'ExitProcess'
import msvcrt,\
printf, 'printf'
entry $
invoke icogen_create_ico, fname, ico, ico_sz, 2, 255
test eax, eax
jne .e
cinvoke printf, s
jmp .s
.e: cinvoke printf, e
.s: invoke ExitProcess, 0
ico dd 16, 24, 32, 48, 128, 256
ico_sz = ($ - ico) / 4
fname db 'icon.ico', 0
s db 'Successfully completed!', 13, 10, 0
e db 'Error!', 13, 10, 0
на Python:
#!/usr/bin/env py -3
import ctypes
import struct
icogen_dll = ctypes.windll.LoadLibrary('icogen_dll.dll')
sz = 16, 24, 32, 48, 128, 256
if not icogen_dll.icogen_create_ico(b'icon.ico', struct.pack(str(len(sz)) + 'I', *sz), len(sz), 2, 255):
print("Successfully completed!\n")
else:
print("Error!\n")