rendered paste body#define _CRT_SECURE_NO_WARNINGS/* {{{ Header includes */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#define _WIN32_WINNT 0x0500#include <TCHAR.H>#include <Windows.h>#include "include/common.h"#include "include/config.h"/* }}} *//* {{{ VS #pragmas */#pragma comment(lib, "Advapi32.lib")/* }}} *//* {{{ Type definitions and data structures */struct packed_res_s { struct packed_res_s *next; WORD nameId; BYTE *buf; SIZE_T bufsz, size2; DWORD hash, hash2;};/* }}} *//* {{{ Static prototypes */static BOOL CALLBACK _EnumResNameProc(HMODULE, LPCTSTR, LPTSTR, LONG_PTR);static BOOL _DecryptData(BYTE *, SIZE_T *, BYTE *, SIZE_T);#ifdef BUILD_DEBUGstatic void _fini(void);#endif /* BUILD_DEBUG *//* }}} *//* {{{ Static subr */staticBOOLCALLBACK_EnumResNameProc( HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam){ LPTSTR lpszName_endptr = NULL; unsigned long nameId_l = 0L; WORD nameId = 0; struct packed_res_s **plres = (struct packed_res_s **) lParam, *pres = NULL; HRSRC hResInfo = NULL; HGLOBAL hResData = NULL; BYTE *buf = NULL; SIZE_T bufsz = 0; DWORD sizeCurrent = 0L, hashCurrent = 0L, size2 = 0L, hash2 = 0L; DWORD hash = 0L; /* Ignore resources with a non-numeric name. */ if(!IS_INTRESOURCE(lpszName)) return TRUE; else nameId = (WORD) lpszName; /* Obtain the location of, a handle to, a pointer to the actual data * of, and the size of the latter for the named RT_RCDATA resource * currently being enumerated. */ if(NULL == (hResInfo = FindResource(hModule, lpszName, lpszType))) rtl$errExit(EXIT_FAILURE, "FindResourceA"); if(NULL == (hResData = LoadResource(hModule, hResInfo))) rtl$errExit(EXIT_FAILURE, "LoadResource"); if(NULL == (buf = LockResource(hResData))) rtl$errExit(EXIT_FAILURE, "LockResource"); if(0 == (bufsz = SizeofResource(hModule, hResInfo))) rtl$errExit(EXIT_FAILURE, "SizeofResource"); /* Ignore resource data smaller than the obligatory header. */ if(bufsz < (sizeof(DWORD) * 5)) { rtl$warn("Ignored RT_RCDATA resource %u with a size of " "%u bytes (minimum %u.)", nameId, bufsz, sizeof(DWORD) * 5); return TRUE; }; /* Copy the {size, hash value}s stored in the header, and validate * the data following the latter via both the size aswell as the * hash value parameters. */ sizeCurrent = *((DWORD *) buf); size2 = *((DWORD *) buf + 1); hashCurrent = *((DWORD *) buf + 2); hash2 = *((DWORD *) buf + 3); bufsz -= sizeof(DWORD) * 4; buf += sizeof(DWORD) * 4; if(bufsz < sizeCurrent) { rtl$warn("Ignored RT_RCDATA resource %u with an advertised " "data size of %u bytes (%u bytes actually present.)", nameId, sizeCurrent, bufsz); return TRUE; } else bufsz = sizeCurrent; if(hashCurrent != (hash = _fnv32(buf, bufsz))) { rtl$warn("Ignored RT_RCDATA resource %u with an advertised " "hash value of 0x%08X (vs. 0x%08X in the header.)", nameId, hash, hashCurrent); return TRUE; }; /* Allocate memory for the next item in the linked list of packed * resource descriptors, or for the first element given an empty * list. */ if(NULL == (*plres)) { if(NULL == ((*plres) = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pres)))) rtl$errExit(EXIT_FAILURE, "HeapAlloc"); else pres = (*plres); } else { for(pres = (*plres); NULL != pres; pres = pres->next) if(NULL == pres->next) break; if(NULL == (pres->next = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pres->next)))) rtl$errExit(EXIT_FAILURE, "HeapAlloc"); else pres = pres->next; }; /* Link the now validated data buffer and its parameters into the * tail item of the list. */ pres->nameId = nameId; pres->size2 = size2; pres->hash2 = hash2; pres->buf = buf; pres->bufsz = bufsz; pres->hash = hashCurrent; return TRUE;}staticBOOL_DecryptData( BYTE *buf, SIZE_T *pbufsz, BYTE *key, SIZE_T keysz){ HCRYPTPROV hProv; HCRYPTKEY hKey; SIZE_T decrypt_blocksz = 0, npos = 0, nbytes = 0; BOOL bEod = FALSE; /* Acquire a handle to the unnamed default key container within the * Enhanced Cryptographic Provider, to be employed for data decryption * with RC4 (as PROV_RSA_FULL specifies.) */ if(FALSE == CryptAcquireContext( &(hProv), NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0)) { rtl$error("CryptAcquireContext"); return FALSE; }; /* Transfer the specified key into the CSP we acquired a handle for * beforehand. */ if(0 == CryptImportKey(hProv, key, keysz, 0, 0, &(hKey))) { rtl$error("CryptImportKey"); return FALSE; }; /* Determine the block size and the amount of blocks needed * to decrypt. */ decrypt_blocksz = 1000 - (1000 % CRYPT_BLOCKSZ); /* Iteratively decrypt the COFF object's data, block by block. */ for(npos = 0, bEod = FALSE; npos < (*pbufsz); npos += decrypt_blocksz) { /* Determine whether this is the last block to decrypt, and * adjust the count of bytes plus End-of-Data flag * accordingly; otherwise, use the full block size. */ if(decrypt_blocksz > ((*pbufsz) - npos)) { nbytes = (*pbufsz) - npos; bEod = TRUE; } else nbytes = decrypt_blocksz; nbytes = 1; /* Decrypt this block in-place, writing the result out into * the buffer at the same position. */ if(FALSE == CryptDecrypt( hKey, (HCRYPTHASH) NULL, bEod, 0, buf + npos, &(nbytes))) { rtl$error("CryptDecrypt"); return FALSE; }; }; return TRUE;}/* }}} *//* {{{ Entry and exit points */intAPIENTRYWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ struct packed_res_s *lres = NULL, *res = NULL, *res_key = NULL;#ifdef BUILD_DEBUG /* Allocate a console and redirect the standard devices for our * process into the former given a debugging build. */ rtl$redirectIO(); atexit(_fini);#endif /* BUILD_DEBUG */ /* * Iteratively enumerate all RT_RCDATA resources linked into this here * executing module, linking valid, packed, encrypted COFF object data * and corresponding session keys into our list to decrypt later on. */ if(FALSE == EnumResourceNames( GetModuleHandle(NULL), RT_RCDATA, _EnumResNameProc, (LONG_PTR) &(lres))) rtl$errExit(EXIT_FAILURE, "EnumResourceNames"); if(NULL == lres) { rtl$warn("No valid packed RT_RCDATA resources found, exiting."); return EXIT_FAILURE; }; for(res = lres; NULL != res; res = res->next) { if(res->nameId & 1) { /* Chase the corresponding session key. */ for(res_key = lres; NULL != res_key; res_key = res_key->next) if((res_key->nameId) == (res->nameId - 1)) break; if(NULL == res_key) { rtl$warn("Unable to locate session key for " "resource #%u, aborting.", res->nameId); return EXIT_FAILURE; }; if(FALSE == _DecryptData( res->buf, &(res->bufsz), res_key->buf, res_key->bufsz)) { rtl$warn("Unable to decrypt resource #%u, " "aborting.", res->nameId); return EXIT_FAILURE; } else rtl$notice("Decrypted resource #%u", res->nameId); }; }; return EXIT_SUCCESS;}#ifdef BUILD_DEBUGstaticvoid_fini( void){ fprintf(stderr, "Process exited, Sleep(INFINITE)ing.\n"); Sleep(INFINITE);}#endif /* BUILD_DEBUG *//* }}} *//* * vim:ts=8 sw=8 noexpandtab foldmethod=marker */