├── DecryptNSISPayload.exe ├── DecryptorSrc ├── DecryptNSISPayload.sdf ├── DecryptNSISPayload.sln ├── DecryptNSISPayload.v12.suo └── DecryptNSISPayload │ ├── DecryptNSISPayload.vcxproj │ ├── DecryptNSISPayload.vcxproj.filters │ ├── DecryptNSISPayload.vcxproj.user │ └── main.cpp ├── README.md └── extract_ransom_from_nsis.py /DecryptNSISPayload.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepinstinct/NSISExtractor/cdf1dd6825798011fe34152dd7e8eba88d59ad56/DecryptNSISPayload.exe -------------------------------------------------------------------------------- /DecryptorSrc/DecryptNSISPayload.sdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepinstinct/NSISExtractor/cdf1dd6825798011fe34152dd7e8eba88d59ad56/DecryptorSrc/DecryptNSISPayload.sdf -------------------------------------------------------------------------------- /DecryptorSrc/DecryptNSISPayload.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DecryptNSISPayload", "DecryptNSISPayload\DecryptNSISPayload.vcxproj", "{8F5A6565-E90C-4BF9-AEA2-BA6DECC5466F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {8F5A6565-E90C-4BF9-AEA2-BA6DECC5466F}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {8F5A6565-E90C-4BF9-AEA2-BA6DECC5466F}.Debug|Win32.Build.0 = Debug|Win32 16 | {8F5A6565-E90C-4BF9-AEA2-BA6DECC5466F}.Release|Win32.ActiveCfg = Release|Win32 17 | {8F5A6565-E90C-4BF9-AEA2-BA6DECC5466F}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /DecryptorSrc/DecryptNSISPayload.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepinstinct/NSISExtractor/cdf1dd6825798011fe34152dd7e8eba88d59ad56/DecryptorSrc/DecryptNSISPayload.v12.suo -------------------------------------------------------------------------------- /DecryptorSrc/DecryptNSISPayload/DecryptNSISPayload.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {8F5A6565-E90C-4BF9-AEA2-BA6DECC5466F} 15 | Win32Proj 16 | DecryptNSISPayload 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 55 | true 56 | MultiThreadedDebug 57 | 58 | 59 | Console 60 | true 61 | 62 | 63 | 64 | 65 | Level3 66 | 67 | 68 | MaxSpeed 69 | true 70 | true 71 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 72 | true 73 | MultiThreaded 74 | 75 | 76 | Console 77 | true 78 | true 79 | true 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /DecryptorSrc/DecryptNSISPayload/DecryptNSISPayload.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;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 | -------------------------------------------------------------------------------- /DecryptorSrc/DecryptNSISPayload/DecryptNSISPayload.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | E:\Development\DecryptNSISPayload\DecryptorSrc\info info output 5 | WindowsLocalDebugger 6 | 7 | -------------------------------------------------------------------------------- /DecryptorSrc/DecryptNSISPayload/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Since RtlDecompressBuffer is a function inside WDK, just load it dynamically 6 | typedef NTSTATUS(__stdcall *RtlDecompressBuffer)( 7 | _In_ USHORT CompressionFormat, 8 | _Out_ PUCHAR UncompressedBuffer, 9 | _In_ ULONG UncompressedBufferSize, 10 | _In_ PUCHAR CompressedBuffer, 11 | _In_ ULONG CompressedBufferSize, 12 | _Out_ PULONG FinalUncompressedSize 13 | ); 14 | 15 | typedef struct fileOutputDetails { 16 | DWORD compressedBufferSize; 17 | DWORD uncompressedBufferSize; 18 | DWORD encryptedContentSize; 19 | PBYTE beginningOfEncryptedData; 20 | } encDetails; 21 | 22 | PBYTE OpenAndReadFile(LPSTR filePath, DWORD *fileSize) 23 | { 24 | BYTE *fileContent = NULL; 25 | DWORD numberOfBytesRead = 0; 26 | 27 | HANDLE hFile = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 28 | 29 | if (NULL == hFile) { 30 | printf("Could not open NSIS file. GetLastError = %d\n", GetLastError()); 31 | goto end; 32 | } 33 | 34 | *fileSize = GetFileSize(hFile, NULL); 35 | 36 | fileContent = (PBYTE)VirtualAlloc(NULL, *fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 37 | 38 | if (NULL == fileContent) { 39 | printf("Allocation failed for fileContent. GetLastError = %d\n", GetLastError()); 40 | goto end; 41 | } 42 | 43 | if (FALSE == ReadFile(hFile, fileContent, *fileSize, &numberOfBytesRead, NULL)) { 44 | printf("ReadFile failed. GetLastError = %d\n", GetLastError()); 45 | goto end; 46 | } 47 | 48 | if (0 == numberOfBytesRead) { 49 | goto end; 50 | } 51 | 52 | end: 53 | if (NULL != hFile) { 54 | CloseHandle(hFile); 55 | hFile = NULL; 56 | } 57 | 58 | return fileContent; 59 | } 60 | 61 | PBYTE DecryptContent(PVOID encContent, DWORD encryptedContentSize, BYTE* encKey, DWORD encKeyLenInBytes) 62 | { 63 | HCRYPTPROV hProv = NULL; 64 | HCRYPTHASH hHash = NULL; 65 | HCRYPTKEY hKey = NULL; 66 | 67 | if (FALSE == CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { 68 | // printf("CryptAcquireContext failed. GetLastError = %d\n", GetLastError()); 69 | return NULL; 70 | } 71 | 72 | if (FALSE == CryptCreateHash(hProv, 0x8003, 0, 0, &hHash)) { 73 | // printf("CryptCreateHash failed. GetLastError = %d\n", GetLastError()); 74 | return NULL; 75 | } 76 | 77 | // CryptHashData requires exact size without null-terminated, so decrease it by 1 78 | if (FALSE == CryptHashData(hHash, encKey, encKeyLenInBytes, CRYPT_USERDATA)) { 79 | // printf("CryptHashData failed. GetLastError = %d\n", GetLastError()); 80 | return NULL; 81 | } 82 | 83 | if (FALSE == CryptDeriveKey(hProv, CALG_AES_256, hHash, 1, &hKey)) { 84 | // printf("CryptDeriveKey failed. GetLastError = %x\n", GetLastError()); 85 | return NULL; 86 | } 87 | 88 | if (FALSE == CryptDestroyHash(hHash)) { 89 | // printf("CryptDestroyHash failed. GetLastError = %x\n", GetLastError()); 90 | return NULL; 91 | } 92 | 93 | if (FALSE == CryptDecrypt(hKey, NULL, TRUE, NULL, (BYTE*)encContent, &encryptedContentSize)) { 94 | // printf("CryptDecrypt failed. GetLastError = %d\n", GetLastError()); 95 | return NULL; 96 | } 97 | 98 | if (FALSE == CryptDestroyKey(hKey)) { 99 | // printf("CryptDestroyKey failed. GetLastError = %d\n", GetLastError()); 100 | return NULL; 101 | } 102 | 103 | if (FALSE == CryptReleaseContext(hProv, 0)) { 104 | // printf("CryptReleaseContext failed. GetLastError = %d\n", GetLastError()); 105 | return NULL; 106 | } 107 | 108 | return (PBYTE)encContent; 109 | } 110 | 111 | PBYTE ExtractDataAndDecrypt(PBYTE codeContent, LPWSTR encKey, DWORD encKeyLenInBytes, DWORD *finalUncompressedSize, DWORD currentIndex, DWORD fileSize) 112 | { 113 | encDetails details = { 0 }; 114 | PDWORD encHeader = NULL; 115 | PVOID encryptedContent = NULL; 116 | PBYTE decryptedContent = NULL, decompressContent = NULL; 117 | RtlDecompressBuffer _RtlDecompressBuffer = (RtlDecompressBuffer)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlDecompressBuffer"); 118 | 119 | encHeader = (PDWORD)(codeContent + currentIndex); 120 | 121 | details.beginningOfEncryptedData = (codeContent + currentIndex + 0x10); 122 | 123 | details.uncompressedBufferSize = *(encHeader + 0x2) + 0x3E8; 124 | 125 | encryptedContent = VirtualAlloc(NULL, details.uncompressedBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 126 | 127 | if (NULL == encryptedContent) { 128 | // printf("Allocation failed for uncompressed size. GetLastError = %d\n", GetLastError()); 129 | goto end; 130 | } 131 | 132 | details.encryptedContentSize = *(encHeader + 0x2); 133 | 134 | // Since we are about to copy the encrypted data, it must be smaller than its file size 135 | if (details.encryptedContentSize > fileSize) { 136 | goto end; 137 | } 138 | 139 | if ((DWORD)details.beginningOfEncryptedData - (DWORD)codeContent + details.encryptedContentSize > fileSize) { 140 | goto end; 141 | } 142 | 143 | CopyMemory(encryptedContent, details.beginningOfEncryptedData, details.encryptedContentSize); 144 | 145 | decryptedContent = DecryptContent(encryptedContent, details.encryptedContentSize, (PBYTE)encKey, encKeyLenInBytes - 1); 146 | 147 | if (NULL == decryptedContent) { 148 | goto end; 149 | } 150 | 151 | details.uncompressedBufferSize = *(encHeader + 0x1); 152 | 153 | decompressContent = (PBYTE)VirtualAlloc(NULL, details.uncompressedBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 154 | 155 | if (NULL == decompressContent) { 156 | // printf("Allocation failed for decompressContent. GetLastError = %d\n", GetLastError()); 157 | goto end; 158 | } 159 | 160 | details.compressedBufferSize = (DWORD)*encHeader; 161 | 162 | // Decompress it 163 | if (0 == _RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, decompressContent, details.uncompressedBufferSize, decryptedContent, details.compressedBufferSize, finalUncompressedSize)) { 164 | // printf("_RtlDecompressBuffer failed. GetLastError = %d", GetLastError()); 165 | goto end; 166 | } 167 | 168 | *finalUncompressedSize = details.uncompressedBufferSize; 169 | 170 | end: 171 | if (NULL != encryptedContent) { 172 | // Release what we don't need anymore 173 | VirtualFree(encryptedContent, details.uncompressedBufferSize, MEM_DECOMMIT | MEM_RELEASE); 174 | encryptedContent = NULL; 175 | } 176 | 177 | return decompressContent; 178 | 179 | } 180 | 181 | int main(int argc, char **argv[]) 182 | { 183 | PBYTE nsisContent = NULL; 184 | PBYTE codeContent = NULL; 185 | LPWSTR encKey = NULL; 186 | DWORD keyLen = 0, keyLenUnicodeBytesSize = 0, uncompressedSize = 0, fileSize = 0, currentIndex = 0; 187 | PBYTE uncompressedContent = NULL; 188 | FILE *fp = NULL; 189 | 190 | if (4 != argc) { 191 | printf("Usage: %s InputFile EncKey RansomwareOutput", argv[0]); 192 | return 0; 193 | } 194 | 195 | codeContent = OpenAndReadFile((LPSTR)argv[1], &fileSize); 196 | 197 | // Convert the key to unicode 198 | keyLen = strlen((char*)argv[2]); 199 | 200 | keyLenUnicodeBytesSize = keyLen * 2 + 1; 201 | 202 | encKey = (LPWSTR)malloc(keyLenUnicodeBytesSize); 203 | 204 | MultiByteToWideChar(CP_OEMCP, 0, (LPCCH)argv[2], -1, encKey, keyLen * 2 + 1); 205 | 206 | // Since the header is in different location every time, use brute force to extract the uncompressed content 207 | for (currentIndex = 0; currentIndex < fileSize; currentIndex++) { 208 | uncompressedContent = ExtractDataAndDecrypt(codeContent, encKey, keyLenUnicodeBytesSize, &uncompressedSize, currentIndex, fileSize); 209 | if (NULL == uncompressedContent) { 210 | continue; 211 | } else if (uncompressedContent[0] == 'M' && uncompressedContent[1] == 'Z') { 212 | fopen_s(&fp, (char*)argv[3], "wb"); 213 | fwrite(uncompressedContent, sizeof(BYTE), uncompressedSize, fp); 214 | fclose(fp); 215 | VirtualFree(uncompressedContent, uncompressedSize, MEM_DECOMMIT | MEM_RELEASE); 216 | break; 217 | } 218 | else { 219 | VirtualFree(uncompressedContent, uncompressedSize, MEM_DECOMMIT | MEM_RELEASE); 220 | } 221 | } 222 | 223 | return 0; 224 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NSIS Extractor 2 | 3 | Usage: 4 | 5 | python extract_ransom_from_nsis.py 6 | 7 | Pre-requesit: 8 | * 7-Zip (installed on c:\Program Files (x86)\7-Zip\) 9 | -------------------------------------------------------------------------------- /extract_ransom_from_nsis.py: -------------------------------------------------------------------------------- 1 | from os import listdir, remove, makedirs 2 | from os.path import isfile, join, exists 3 | import sys 4 | import subprocess 5 | 6 | LOCATION_7ZIP = r"c:\Program Files (x86)\7-Zip\7z.exe" 7 | EXTRACTOR_LOCATION = r"C:\Users\Generic\Desktop\DecryptNSISPayload.exe" 8 | 9 | def main(): 10 | if 3 != len(sys.argv): 11 | print "Usage: " + sys.argv[0] + " NSISFile OutputPath" 12 | return 13 | 14 | archive_name = sys.argv[1] 15 | out_path = sys.argv[2] 16 | 17 | if exists(out_path): 18 | makedirs(out_path) 19 | 20 | # extract the content of NSIS to out_path 21 | subprocess.call(LOCATION_7ZIP + r' e -y -o' + '\"' + out_path + '\"' + " " + '\"' + archive_name + '\"') 22 | 23 | # Execute the extractor for all files and check if the output file were created 24 | files_list = [f for f in listdir(out_path) if isfile(join(out_path, f))] 25 | for file_name in files_list: 26 | subprocess.call(EXTRACTOR_LOCATION + " \"" + join(out_path, file_name) + "\" \"" + file_name + "\" \"" + join(out_path, "ransomware.exe_do_not_execute") + "\"") 27 | if exists(join(out_path, "out.out")): 28 | break 29 | 30 | for file_name in files_list: 31 | remove(join(out_path, file_name)) 32 | 33 | if __name__ == "__main__": 34 | main() --------------------------------------------------------------------------------