├── 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()
--------------------------------------------------------------------------------