Пишем плагин base64decoder к HIEW
Думаю, среди ревёрсеров мало кто не знает про такую замечательную программу, как hiew. Не буду перечислять все её возможности (а их полно), а сразу перейду к теме. Дело в том, что hiew чрезвычайно удобно использовать для выдёргивания shell кодов из эксплойтов. Зачастую, шел коды в эксплойтах хранятся в base64 закодированном виде. Не знаю, как вы, но я, чтобы конвертировать шелл код в бинарный вид, использовал notepad++. Это было неудобно, зато работало. Делалось это следующим образом: в HIEW выделялись base64 данные, затем сохранялись в файл. Далее файл открывался блокнотом, и, соответственно, конвертировался, затем сохранялся. Однажды, нужно было проанализировать подозрительные файлы, возможно, эксплойты, их было около семи штук. В этот момент образовался вопрос: а нельзя ли прямо из HIEW сохранять выделенные байты, конвертированные из base64 в нормальный вид? Конечно же можно! Нужно лишь скачать плагин. Только вот проблема, такого плагина я не нашёл. Тогда на помощь приходит HIEW SDK и Visual Studio. Sdk вы можете взять тут. Вам понадобится два файла: hem.h и HiewGate.c. Также тут есть и мануал, в котором вы можете почерпнуть дополнительную информацию.
Плагин, который мы будем писать, представляет из себя нечто иное, как динамическую библиотеку, с расширением .hem (Hiew External Module). Она будет подгружаться самим Hiew. Плагины должны находиться в установленном месте hiew\hem. Обязательно должны быть следующие функции: Hem_EntryPoint и Hem_Load. В Hem_Load передаётся структура HIEWINFO_TAG, содержащая всю информацию о плагине. В HIEWINFO_TAG описаны следующие вещи: в каком режиме должен быть доступен плагин (текстово1, шестнадцатеричный или режим дизассемблера), под какую версию написан плагин, какое расширение у файлов должно быть, чтобы плагин был активен, кто написал плагин, должны ли быть выделены байты. Вся эта информация описывается в данной структуре, которая должна быть заполнена и применена вызовом HiewGate_Set, в Hem_Load.
Прежде чем начнём, давайте рассмотрим работу некоторых функций, которые мы будем использовать из sdk.
HiewGate_GetMemory | Выделяет память, возвращает указатель на неё |
HiewGate_FreeMemory | Освобождает память |
HiewGate_GetData | Читает выделенные маркером байты, возвращает количество прочитанных байт |
Hem_Load | Функция для инициализации плагина |
Hem_Unload | Функция для выгрузки плагина |
Hem_EntryPoint | Точка входа в плагин |
HiewGate_SetErrorMsg | ВВывод сообщения об ошибке |
HiewGate_FileRead | Чтение из файла |
HiewGate_Window | Показывает окно с сообщением. Тут можно организовать что-то типа меню |
Итак, приступим к кодингу. Создаём проект в студии, сразу настройте проект так, чтобы имя файла было с расширением hem, это для удобства. Также не забудьте в опциях C/C++/Code Generation/Runtime Library выставить значение Multi-threaded (/MT). Если этого не сделать, то при загрузке плагина на некоторых машинах, может вылазить ошибка 126.
При реализации идеи нужно помнить, что количество выделенных байт должно быть кратным 4.
Сам код плагина:
base64decoder.h
#include "SDK\hem.h" #define VER_MAJOR 1 #define VER_MINOR 00 #define FILE_NAME_MAX 20 int HEM_API Hem_Unload(void), Hem_EntryPoint(HEMCALL_TAG *hemCall); HEMINFO_TAG hemInfo = { sizeof(HEMINFO_TAG), sizeof(int), 0, // reserved HEM_SDK_VERSION_MAJOR, HEM_SDK_VERSION_MINOR, VER_MAJOR, VER_MINOR, HEM_FLAG_MARKEDBLOCK | //active only when a block is marked HEM_FLAG_HEX | //active in Hex mode HEM_FLAG_TEXT | //active in Text mode HEM_FLAG_FILEMASK, //active for files of any type, as well as for disks 0, // reserved Hem_EntryPoint, Hem_Unload, NULL, 0,0,0,0, // reserved "Base64Decoder", // short name "Base64 Decoder", // full name "*******************************************", "Base64 Decoder (c) Neo", //description "*******************************************" }; ////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// #define LineDialogCount 2 #define MaxSimbolsInDialogLine 100 const HEM_BYTE *DIALOG[] = { (HEM_BYTE*) "Yes", (HEM_BYTE*) "No" }; #define LineDialogDoneCount 2 #define MaxSimbolsInDialogDoneLine 15 const HEM_BYTE *DialogDone[] = { (HEM_BYTE*)"It`s Ok", (HEM_BYTE*)"All Done" }; char *ResultFileName = NULL; char *ResultFullFileName = NULL; char *CurrentFullFileName = NULL; int bOnHexLine = 0; //чтобы ввод был по умолчанию был буквами,а не цифрами
base64decoder.cpp
/* Base64 Decoder v1 - a plagin for Hiew. This plugin takes the selected bytes of the encoded string and decodes them. The result will be saved to a file. Neo © */ //#define DEBUG #include <Windows.h> #include <stdio.h> #include "Shlwapi.h" #pragma comment(lib, "Shlwapi.lib") #include <Wincrypt.h> #pragma comment (lib, "Crypt32.lib") #include "base64decoder.h" int HEM_EXPORT Hem_Load(HIEWINFO_TAG *hiewInfo) { HiewGate_Set(hiewInfo); hiewInfo->hemInfo = &hemInfo; return ((hiewInfo->hiewVerMajor * 100 + hiewInfo->hiewVerMinor < 745) ? HEM_ERR_HIEW_VERSION_INVALID : HEM_OK); } int HEM_API Hem_Unload() { #ifdef DEBUG OutputDebugStringA("base64decode Plagin Unload"); #endif // DEBUG return(HEM_OK); } char *StripFileName(char *fileName) { char *pos = strrchr(fileName, '\\') + 1; if (pos != NULL) *pos = '\0'; return fileName; } /* It displays a dialog box asking whether the user want to overwrite the file if it exists. Returns - if FullFileName dont exists, or User wont it overwrite. Otherwise - False. */ BOOL OverwriteFileIfExistsDialog(char *FullFileName) { if (PathFileExistsA(FullFileName)) { char *title = (char *)HiewGate_GetMemory(MAX_PATH * 2); ZeroMemory(title, MAX_PATH * 2); sprintf_s(title, MAX_PATH * 2, "File %s Allready Exists! OVERWRITE it?", FullFileName); int _case = HiewGate_Menu( (HEM_BYTE*)title, (HEM_BYTE**)&DIALOG, LineDialogCount, MaxSimbolsInDialogLine, 2, //Defoult - No NULL, NULL, NULL, NULL); HiewGate_FreeMemory((HEM_BYTE *)title); //1 - Yes //2 - No return (_case == 1) ? TRUE : FALSE; } return TRUE; } BOOL Base64_Decode(CHAR *pInput, size_t cbInput, CHAR **pOutput, size_t *pOutputLen) { BOOL bRetVal = FALSE; DWORD nBufSize = 0; if (!pInput || !pOutput || !pOutputLen) return bRetVal; if (CryptStringToBinaryA(pInput, cbInput, CRYPT_STRING_BASE64, NULL, &nBufSize, NULL, NULL) && nBufSize > 0) if ((*pOutput = (char *)HiewGate_GetMemory(nBufSize + 1)) != NULL) if (CryptStringToBinaryA(pInput, cbInput, CRYPT_STRING_BASE64, (byte *)*pOutput, &nBufSize, NULL, NULL)) bRetVal = TRUE; *pOutputLen = nBufSize; return(bRetVal); } BOOL WriteToFile(LPCSTR fileName, LPVOID buf, DWORD size) { DWORD rw; BOOL result = false; HANDLE f = CreateFileA(fileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); #ifdef DEBUG if (f == INVALID_HANDLE_VALUE) OutputDebugStringA("INVALID_HANDLE_VALUE"); else OutputDebugStringA("HANDLE good!"); #endif // DEBUG if (f != INVALID_HANDLE_VALUE) if (WriteFile(f, buf, size, &rw, NULL)) if (size == rw) result = true; CloseHandle(f); return result; } int HEM_API Hem_EntryPoint(HEMCALL_TAG *hemCall) { HIEWGATE_GETDATA hiewData; int result = -1; int rc = HiewGate_GetData(&hiewData); #ifdef DEBUG OutputDebugStringA("base64decode Plagin Entry Point"); #endif // DEBUG if (rc == HEM_OK) { HEM_QWORD blockSize = hiewData.sizeMark; HEM_BYTE *pBlock = HiewGate_GetMemory(blockSize); ZeroMemory(pBlock, blockSize); if (!pBlock) return HiewGate_SetErrorMsg((HEM_BYTE *)"GetMemory() error"); ResultFileName = (char *)HiewGate_GetMemory(FILE_NAME_MAX); //short file name with base64 decoded date ZeroMemory(ResultFileName, FILE_NAME_MAX); if (HiewGate_GetStringDual((HEM_BYTE *)"Save To File", (HEM_BYTE *)ResultFileName, FILE_NAME_MAX, 0, &bOnHexLine) == HEM_INPUT_ESC) { HiewGate_FreeMemory((HEM_BYTE *)ResultFileName); return HEM_INPUT_ESC; } ResultFullFileName = (char *)HiewGate_GetMemory(MAX_PATH); //file name with base64 decoded date ZeroMemory(ResultFullFileName, MAX_PATH); CurrentFullFileName = (char *)HiewGate_GetMemory(MAX_PATH); //current file name,opened by hiew ZeroMemory(CurrentFullFileName, MAX_PATH); memcpy(CurrentFullFileName, hiewData.filename, strlen((char *)hiewData.filename)); ResultFullFileName = StripFileName(CurrentFullFileName); lstrcatA(ResultFullFileName, (char *)ResultFileName); #ifdef DEBUG OutputDebugStringA(ResultFullFileName); #endif // DEBUG if (OverwriteFileIfExistsDialog(ResultFileName)) //file not exists or need to overwrite { HiewGate_MessageWaitOpen(NULL); //Show Processing.... if (HiewGate_FileRead(hiewData.offsetMark1, blockSize, pBlock) != blockSize) { HiewGate_FreeMemory((HEM_BYTE *)ResultFileName); HiewGate_FreeMemory((HEM_BYTE *)CurrentFullFileName); HiewGate_FreeMemory((HEM_BYTE *)ResultFullFileName); HiewGate_FreeMemory(pBlock); #ifdef DEBUG OutputDebugStringA("Read Bad"); #endif // DEBUG return HiewGate_SetErrorMsg((HEM_BYTE *)"Read Selected date error!"); } else { #ifdef DEBUG OutputDebugStringA("Read Good"); #endif // DEBUG HEM_BYTE *dst = NULL; size_t converted = 0; BOOL Base64Status = Base64_Decode((char *)pBlock, blockSize, (char **)&dst, &converted); if (/*converted < blockSize && */Base64Status) { if (WriteToFile(ResultFullFileName, dst, converted)) { #ifdef DEBUG OutputDebugStringA("WriteGood!"); #endif // DEBUG result = HEM_OK; } else { #ifdef DEBUG OutputDebugStringA("WriteBad"); #endif // DEBUG HiewGate_SetErrorMsg((HEM_BYTE *)"Can`t to WriteFile!"); } } else { #ifdef DEBUG OutputDebugStringA("Data can not be converted! May be you forget, that Bytes must be in range: [A..Z,a..z,+,=]"); #endif // DEBUG result = -2; } HiewGate_FreeMemory(dst); HiewGate_FreeMemory((HEM_BYTE *)ResultFileName); HiewGate_FreeMemory((HEM_BYTE *)CurrentFullFileName); HiewGate_FreeMemory((HEM_BYTE *)ResultFullFileName); HiewGate_FreeMemory(pBlock); } HiewGate_MessageWaitClose(); } if (result == HEM_OK) HiewGate_Window((HEM_BYTE*)"base64 Decoder", (HEM_BYTE**)&DialogDone, LineDialogDoneCount, MaxSimbolsInDialogDoneLine, NULL, NULL); else if (result == -2) HiewGate_SetErrorMsg((HEM_BYTE *)"Data can not be converted! May be you forget, that Bytes must be in range: [A..Z,a..z,+,=] and number of bytes should be divisible 4"); else HiewGate_SetErrorMsg((HEM_BYTE *)"Unknown Error! I am sorry."); return result; } }
Результат работы плагина:
- закодированный в base64 данные
- Выделяем байты
- Выбираем base64decoder плагин
- Созраняем расшифрованный данные
- Готово!
Исходники и сам плагин вы можете взять тут: base64decoder.
If you found an error, highlight it and press Shift + Enter or click here to inform us.