451: Data-Trash Generator
DTRASH v 1.00
Data-Trash Generator
DTRASH is a garbage generator using data. The principle of its operation is such that it receives a list of addresses that can be used, flags, a buffer, etc. as input, and at the output there is a command in the buffer and its length. In total, the engine is capable of generating about 30-40 commands of various opcodes, except for modifications of the same commands like rcl reg,1 and rcl reg,im. In addition to memory accesses, common registers and operands are used.
Main procedure (C call is used here):
DWORD Dtrash( VOID* DataTable, // pointer to addresses
DWORD DataCnt, // their number
VOID* TrashTable, // table pointer,
// needed by the generator.
VOID* OutBufer, // output buffer
DWORD Flags, // flags
DWORD* Seed, // pointer to seed
DWORD *(RND(DWORD* SEED,DWORD Range)) // pointer to the RNG procedure
);
As an output parameter, the generator returns in EAX the length of the received command.
The list of addresses (addresses) is an array of structures:
typedef struct{
DWORD getd_dRVA
DWORD getd_cRVA
DWORD getd_cSize
DWORD getd_cdType
} node;
Where the second and third fields are ignored, and only getd_RVA is used, the first contains the RVA of the data and getd_cdType, the size of the data in the second byte and the type of access to them. The list itself can be obtained by analyzing the program's access to data, but it is worth remembering that when generating write commands, you should take into account the size of the data, because not the fact that the data is aligned there, i.e. some value (usually dword) is used instead of bytes and words and all variables on the border of this value, so much so that the program does not "know" about it. But even if they are aligned, then it is not known to which border ;)
The generator uses its table to work. It can be included as data in the code, in other words, include its include, or more universally, use a procedure that unpacks the tables (about 300 bytes) into a buffer:
VOID trash_init(
VOID* Ptr // buffer pointer
)
After that, you can pass the address of the buffer to the main procedure and call it.
The following flags are used to set the garbage generation options:
DTF_READ 0000000000000000b generate read commands
DTF_WRITE 0000000000000001b generate write commands
DTF_MFLAGS 0000000000000010b use garbage flags?
DTF_EAX 0000000100000000b use AL/AX/EAX
DTF_ECX 0000001000000000b use CL/CX/ECX
DTF_EDX 0000010000000000b use DL/DX/EDX
DTF_EBX 0000100000000000b use BL/BX/EBX
DTF_ESP 0001000000000000b use AH/SP/ESP
DTF_EBP 0010000000000000b use CH/BP/EBP
DTF_ESI 0100000000000000b use DH/SI/ESI
DTF_EDI 1000000000000000b use BH/DI/EDI
DTF_ALL 1111111100000000b use all registers
The used registers also depend on the size of the input data. So with a data size of 1 byte and the DTF_EAX flag turned on, only AL will be used, but when the DTF_ESP flag is turned on, AH will also be generated. The same applies to other single-byte registers.
If the data size is 4 bytes, then it can be accessed as a 1/2/4 byte variable.
original russian version
DTRASH v 1.00
Data-Trash Generator
DTRASH является генератором мусора с использованием данных. Принцип его действия таков, что на вход ему подается список адресов, которые можно использовать, флаги, буфер и др., а на выходе имеется команда в буфере и ее длина. Всего движок способен генерировать около 30-40 команд различных опкодов, если не считать модификаций одних и тех же команд типа rcl reg,1 и rcl reg,im.Помимо обращений к памяти используются общие регистры и операнды.
Главная процедура (тут использован C call):
DWORD Dtrash( VOID* DataTable, // указатель на адреса
DWORD DataCnt, // их количество
VOID* TrashTable, // указатель на таблицу,
// необходимую генератору.
VOID* OutBufer, // выходной буфер
DWORD Flags, // флаги
DWORD* Seed, // указатель на seed
DWORD *(RND(DWORD* SEED,DWORD Range)) // указатель на процедуру ГСЧ
);
Как выходной параметр генератор возвращает в EAX длину полученной команды.
Список адресов (адреса) представляет собой массив структур:
typedef struct{
DWORD getd_dRVA
DWORD getd_cRVA
DWORD getd_cSize
DWORD getd_cdType
} node;
Где вторе и третье поля игнорируются, а используются лишь getd_RVA, содержащее RVA данных и getd_cdType- размер данных во втором байте и тип обращения к ним - в первом. Сам список может быть получен путем анализа обращения программы к данным, но стоит помнить, что при генерировании команд на запись следует учесть размер данных т.к. не факт, что там данные выровнены, т.е. используются какая-то величина (чаше dword) вместо байтов и слов и все переменные на границе этой величины, да так, что программа и не "знает" об этом. Но и если выровнены,то неизвестно на какую границу ;)
Генератор использует свою таблицу для работы. Ее можно включать как данные в код, другими словами - включать ее инклудник,либо же,что более универсально, использовать процедуру,которая распакует таблицы (где-то 300 байт) в буфер:
VOID trash_init(
VOID* Ptr // указатель на буфер
)
После этого можно передать адрес буфера в главную процедуру и вызвать ее.
Для задания параметров генерирования мусора используются флаги:
DTF_READ 0000000000000000b генерировать команды на чтение
DTF_WRITE 0000000000000001b генерировать команды на запись
DTF_MFLAGS 0000000000000010b использовать флаги мусором?
DTF_EAX 0000000100000000b использовать AL/AX/EAX
DTF_ECX 0000001000000000b использовать CL/CX/ECX
DTF_EDX 0000010000000000b использовать DL/DX/EDX
DTF_EBX 0000100000000000b использовать BL/BX/EBX
DTF_ESP 0001000000000000b использовать AH/SP/ESP
DTF_EBP 0010000000000000b использовать CH/BP/EBP
DTF_ESI 0100000000000000b использовать DH/SI/ESI
DTF_EDI 1000000000000000b использовать BH/DI/EDI
DTF_ALL 1111111100000000b использовать все регистры
Использованные регистры зависят и от размера входных данных. Так при размере данных в 1 байт и включенном флаге DTF_EAX будет использоваться лишь AL ,но при включении флага DTF_ESP ,будет еще генерироваться и AH. Тоже касается и остальных однобайтовых регистров.
Если размер данных - 4 байта, то к ним может использоваться обращение как к 1/2/4 байтовой переменной.