├── .gitattributes
├── .gitignore
├── MalwareResourceScanner_Console.sln
├── MalwareResourceScanner_Console
├── MalwareResourceScanner_Console.vcxproj
├── MalwareResourceScanner_Console.vcxproj.filters
├── MalwareResourceScanner_Console.vcxproj.user
├── ResourceParser.cpp
├── ResourceParser.h
└── main.cpp
├── README.md
├── tests
├── notepad32.exe_
├── notepad64.exe_
├── xored1
├── xored2
├── xored3
├── xored4
└── xored5
└── tool
└── MalwareResourceScanner_Console.exe
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # =========================
18 | # Operating System Files
19 | # =========================
20 |
21 | # OSX
22 | # =========================
23 |
24 | .DS_Store
25 | .AppleDouble
26 | .LSOverride
27 |
28 | # Icon must ends with two \r.
29 | Icon
30 |
31 | # Visual Studio
32 | Debug
33 | *.sdf
34 | *.opensdf
35 | *.tlog
36 | *.obj
37 | *.idb
38 | *.pdb
39 | *.log
40 | *.lastbuildstate
41 | *.*ilk
42 | *.manifest
43 | *.ipch
44 |
45 |
46 | # Thumbnails
47 | ._*
48 |
49 | # Files that might appear on external disk
50 | .Spotlight-V100
51 | .Trashes
52 |
--------------------------------------------------------------------------------
/MalwareResourceScanner_Console.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MalwareResourceScanner_Console", "MalwareResourceScanner_Console\MalwareResourceScanner_Console.vcxproj", "{744FE857-7506-4EBE-8E6A-0FED2D119C78}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Win32 = Debug|Win32
9 | Release|Win32 = Release|Win32
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {744FE857-7506-4EBE-8E6A-0FED2D119C78}.Debug|Win32.ActiveCfg = Debug|Win32
13 | {744FE857-7506-4EBE-8E6A-0FED2D119C78}.Debug|Win32.Build.0 = Debug|Win32
14 | {744FE857-7506-4EBE-8E6A-0FED2D119C78}.Release|Win32.ActiveCfg = Release|Win32
15 | {744FE857-7506-4EBE-8E6A-0FED2D119C78}.Release|Win32.Build.0 = Release|Win32
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/MalwareResourceScanner_Console/MalwareResourceScanner_Console.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {744FE857-7506-4EBE-8E6A-0FED2D119C78}
23 | Win32Proj
24 | MalwareResourceScanner_Console
25 |
26 |
27 |
28 | Application
29 | true
30 | Unicode
31 | v100
32 |
33 |
34 | Application
35 | true
36 | Unicode
37 | v110
38 |
39 |
40 | Application
41 | false
42 | true
43 | Unicode
44 | v100
45 |
46 |
47 | Application
48 | false
49 | true
50 | Unicode
51 | v110
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | true
71 |
72 |
73 | true
74 |
75 |
76 | false
77 |
78 |
79 | false
80 |
81 |
82 |
83 |
84 |
85 | Level3
86 | Disabled
87 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
88 | MultiThreadedDebug
89 |
90 |
91 | Console
92 | true
93 |
94 |
95 |
96 |
97 |
98 |
99 | Level3
100 | Disabled
101 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
102 |
103 |
104 | Console
105 | true
106 |
107 |
108 |
109 |
110 |
111 |
112 | Level3
113 |
114 |
115 | MaxSpeed
116 | true
117 | true
118 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
119 | MultiThreaded
120 |
121 |
122 | Console
123 | true
124 | true
125 | true
126 |
127 |
128 |
129 |
130 | Level3
131 |
132 |
133 | MaxSpeed
134 | true
135 | true
136 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
137 |
138 |
139 | Console
140 | true
141 | true
142 | true
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/MalwareResourceScanner_Console/MalwareResourceScanner_Console.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;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 | Source Files
23 |
24 |
25 |
26 |
27 | Header Files
28 |
29 |
30 |
--------------------------------------------------------------------------------
/MalwareResourceScanner_Console/MalwareResourceScanner_Console.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -d d:\hello\
5 | WindowsLocalDebugger
6 |
7 |
8 | -unpack -scannonpefiles -d c:\samples\
9 | WindowsLocalDebugger
10 |
11 |
12 | -v d:\xored1
13 | WindowsLocalDebugger
14 |
15 |
--------------------------------------------------------------------------------
/MalwareResourceScanner_Console/ResourceParser.cpp:
--------------------------------------------------------------------------------
1 | #include "ResourceParser.h"
2 |
3 | BOOL CResourceParser::LoadFile( LPCWSTR szFileName )
4 | {
5 | DWORD dwNumberOfBytesRead;
6 | HANDLE hFile;
7 | BOOL fResult;
8 |
9 | if (!szFileName)
10 | return FALSE;
11 |
12 | //
13 | // remove old buffer
14 | //
15 | if (m_pBuffer)
16 | {
17 | delete[] m_pBuffer;
18 | m_pBuffer = NULL;
19 | }
20 |
21 | fResult = FALSE;
22 |
23 | //
24 | // open file for read
25 | //
26 | hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
27 | if ( hFile != INVALID_HANDLE_VALUE )
28 | {
29 | m_dwFileSize = GetFileSize(hFile, NULL);
30 | if ( m_dwFileSize != INVALID_FILE_SIZE )
31 | {
32 | //
33 | // allocate new buffer and read the file into our buffer
34 | //
35 | m_pBuffer = new BYTE[ m_dwFileSize ];
36 | SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
37 | if ( !ReadFile(hFile, m_pBuffer, m_dwFileSize, &dwNumberOfBytesRead, NULL) || m_dwFileSize != dwNumberOfBytesRead )
38 | {
39 | //
40 | // something failed, remove the buffer and set it to NULL
41 | //
42 | delete[] m_pBuffer;
43 | m_pBuffer = NULL;
44 | }
45 | else
46 | {
47 | //
48 | // file got successful read into the buffer
49 | // now check if its a valid PE and then read it into the buffer
50 | //
51 | wcscpy_s( m_szFileName, MAX_PATH, szFileName );
52 | if ( IsValidPEInBuffer(m_pBuffer, m_dwFileSize) )
53 | {
54 | fResult = ReadHeaders();
55 | }
56 | }
57 | }
58 | CloseHandle( hFile );
59 | }
60 | return fResult;
61 | }
62 |
63 | BOOL CResourceParser::ReadHeaders()
64 | {
65 | m_DosHeader = (PIMAGE_DOS_HEADER)m_pBuffer;
66 | if ( m_DosHeader && m_DosHeader->e_magic == IMAGE_DOS_SIGNATURE )
67 | {
68 | m_NtHeader = (PIMAGE_NT_HEADERS32)( (char*)m_pBuffer + m_DosHeader->e_lfanew );
69 | m_NtHeader64 = (PIMAGE_NT_HEADERS64)m_NtHeader;
70 | if ( m_NtHeader && m_NtHeader->Signature == IMAGE_NT_SIGNATURE )
71 | {
72 | m_fPePlus = m_NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
73 | return TRUE;
74 | }
75 | }
76 | return FALSE;
77 | }
78 |
79 | BOOL CResourceParser::IsValidPEInBuffer( const BYTE* pBuffer, DWORD dwSize )
80 | {
81 | PIMAGE_DOS_HEADER DosHeader;
82 | PIMAGE_NT_HEADERS32 NtHeader;
83 | PIMAGE_NT_HEADERS64 NtHeader64;
84 | DWORD64 dwTemp;
85 |
86 | if ( pBuffer == NULL || dwSize == 0 )
87 | return FALSE;
88 |
89 | if ( dwSize < (sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER)) ) // test if there are enough bytes for the check
90 | return FALSE;
91 |
92 | __try
93 | {
94 | DosHeader = (PIMAGE_DOS_HEADER)pBuffer;
95 | if ( DosHeader->e_magic == IMAGE_DOS_SIGNATURE )
96 | {
97 | if ( (DWORD)DosHeader->e_lfanew >= dwSize )
98 | return FALSE;
99 |
100 | NtHeader = (PIMAGE_NT_HEADERS) ( (char*)pBuffer + DosHeader->e_lfanew );
101 | NtHeader64 = (PIMAGE_NT_HEADERS64)(NtHeader);
102 | if ( NtHeader->Signature == IMAGE_NT_SIGNATURE )
103 | {
104 | BOOL fPePlus = NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
105 |
106 | if ( fPePlus )
107 | {
108 | //
109 | // 64 bit PE file
110 | //
111 | dwTemp = RvaToFileOffset( NtHeader64->OptionalHeader.AddressOfEntryPoint, pBuffer, NtHeader64->FileHeader.NumberOfSections, TRUE );
112 | if ( dwTemp == (DWORD64)-1 )
113 | return FALSE;
114 |
115 | dwTemp = RvaToFileOffset( NtHeader64->OptionalHeader.BaseOfCode, pBuffer, NtHeader64->FileHeader.NumberOfSections, TRUE );
116 | if ( dwTemp == (DWORD64)-1 )
117 | return FALSE;
118 | }
119 | else
120 | {
121 | //
122 | // 32 bit PE file
123 | //
124 | dwTemp = RvaToFileOffset( NtHeader->OptionalHeader.AddressOfEntryPoint, pBuffer, NtHeader->FileHeader.NumberOfSections, FALSE );
125 | if ( dwTemp == (DWORD64)-1 )
126 | return FALSE;
127 |
128 | dwTemp = RvaToFileOffset( NtHeader->OptionalHeader.BaseOfCode, pBuffer, NtHeader->FileHeader.NumberOfSections, FALSE );
129 | if ( dwTemp == (DWORD64)-1 )
130 | return FALSE;
131 | }
132 |
133 | return TRUE;
134 | }
135 | }
136 | } __except( 1 )
137 | {
138 | //
139 | // exception
140 | //
141 | }
142 | return FALSE;
143 | }
144 |
145 | DWORD64 CResourceParser::RvaToFileOffset( DWORD64 dwRVA )
146 | {
147 | if ( m_fPePlus )
148 | return RvaToFileOffset(dwRVA, m_pBuffer, m_NtHeader64->FileHeader.NumberOfSections, TRUE ); // 64bit PE
149 | return RvaToFileOffset( dwRVA, m_pBuffer, m_NtHeader->FileHeader.NumberOfSections, FALSE ); // 32bit
150 | }
151 |
152 | DWORD64 CResourceParser::RvaToFileOffset( DWORD64 dwRVA, const BYTE* pBuffer, WORD wNumberOfSections, BOOL fPePlus )
153 | {
154 | DWORD64 dwFileOffset;
155 | PIMAGE_SECTION_HEADER pSection;
156 |
157 | dwFileOffset = (DWORD64)-1;
158 |
159 | if ( pBuffer == NULL || wNumberOfSections == 0 )
160 | return dwFileOffset;
161 |
162 | pSection = (PIMAGE_SECTION_HEADER)( (char*)pBuffer + ((IMAGE_DOS_HEADER*)(pBuffer))->e_lfanew + (fPePlus ? sizeof(IMAGE_NT_HEADERS64) : sizeof(IMAGE_NT_HEADERS32)) );
163 |
164 | for ( WORD n = 0; n < wNumberOfSections; n++, pSection++ )
165 | {
166 | if ( pSection && dwRVA >= pSection->VirtualAddress && dwRVA < (pSection->VirtualAddress + pSection->Misc.VirtualSize) )
167 | {
168 | dwFileOffset = dwRVA - pSection->VirtualAddress + pSection->PointerToRawData;
169 | break;
170 | }
171 | }
172 |
173 | return dwFileOffset;
174 | }
175 |
176 | BOOL CResourceParser::ParseResources()
177 | {
178 | DWORD64 dwResourceFileOffset = 0, dwDataFileOffset = 0, dwResourceVA = 0, dwResourceSize = 0;
179 |
180 | ResourceDirectoryTable *lpResRoot, *lpResType, *lpResName;
181 | ResourceDirectoryEntry *lpEntry1, *lpEntry2, *lpEntry3;
182 | ResourceDataEntry *pData;
183 | BOOL fFound = FALSE;
184 | XRayInformation XRayInfo;
185 |
186 | UINT64 ui64Key = 0;
187 |
188 | if ( m_pBuffer == NULL || m_NtHeader == NULL || (m_fPePlus && !m_NtHeader64) )
189 | return FALSE;
190 |
191 | //
192 | // check if we have a valid PE file with a resource section
193 | //
194 |
195 | if ( m_fPePlus )
196 | {
197 | dwResourceVA = m_NtHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
198 | dwResourceSize = m_NtHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
199 | }
200 | else
201 | {
202 | dwResourceVA = m_NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
203 | dwResourceSize = m_NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
204 | }
205 |
206 | if ( dwResourceSize == 0 || dwResourceVA == 0 )
207 | return FALSE;
208 |
209 | //
210 | // get resource section
211 | //
212 | dwResourceFileOffset = RvaToFileOffset( dwResourceVA );
213 |
214 | if ( dwResourceFileOffset == (DWORD64)-1 )
215 | return FALSE;
216 |
217 | lpResRoot = reinterpret_cast( m_pBuffer + dwResourceFileOffset );
218 | if ( lpResRoot->dwCharacteristics != 0 )
219 | return FALSE;
220 |
221 | //
222 | // enumerate all types
223 | //
224 | for ( WORD i = 0; i < lpResRoot->dwNumberOfIDEntries + lpResRoot->dwNumberOfNameEntries; i++)
225 | {
226 | lpEntry1 = reinterpret_cast(lpResRoot + 1) + i;
227 | if ( (lpEntry1->dwDataRva & 0x7FFFFFFF) >= dwResourceSize )
228 | return FALSE;
229 |
230 | lpResType = reinterpret_cast(reinterpret_cast(lpResRoot) + (lpEntry1->dwDataRva & 0x7FFFFFFF));
231 |
232 | //
233 | // call callback function
234 | //
235 | if ( m_lpCallback ) ((ResourceCallbackFunction)m_lpCallback)( static_cast(this), RM_ENUM_TYPE, (LPVOID)lpEntry1, NULL );
236 |
237 | //
238 | // enumerate all names
239 | //
240 | for ( WORD j = 0; j < lpResType->dwNumberOfIDEntries + lpResType->dwNumberOfNameEntries; j++ )
241 | {
242 | lpEntry2 = reinterpret_cast(lpResType + 1) + j;
243 | if ( (lpEntry2->dwDataRva & 0x7FFFFFFF) >= dwResourceSize )
244 | return FALSE;
245 |
246 | lpResName = reinterpret_cast(reinterpret_cast(lpResRoot) + (lpEntry2->dwDataRva & 0x7FFFFFFF));
247 |
248 | //
249 | // call callback function
250 | //
251 | if ( m_lpCallback ) ((ResourceCallbackFunction)m_lpCallback)( static_cast(this), RM_ENUM_NAME, (LPVOID)lpEntry2, NULL );
252 |
253 | //
254 | // enumerate all languages
255 | // now we have access to the offsets of the data
256 | //
257 | for ( WORD k = 0; k < lpResName->dwNumberOfIDEntries + lpResName->dwNumberOfNameEntries; k++ )
258 | {
259 | lpEntry3 = reinterpret_cast(lpResName +1) + k;
260 | if ( (lpEntry3->dwDataRva & 0x7FFFFFFF) >= dwResourceSize )
261 | return FALSE;
262 |
263 | pData = reinterpret_cast(reinterpret_cast(lpResRoot) + (lpEntry3->dwDataRva & 0x7FFFFFFF));
264 |
265 | dwDataFileOffset = RvaToFileOffset( pData->dwDataRva );
266 | if ( dwDataFileOffset == (DWORD64)-1 )
267 | continue; // encrypted resource?
268 |
269 | //
270 | // call callback function
271 | //
272 | if ( m_lpCallback ) ((ResourceCallbackFunction)m_lpCallback)( static_cast(this), RM_ENUM_LANG, (LPVOID)lpEntry3, &dwDataFileOffset );
273 |
274 | //
275 | // check if data is encrypted (invalid offset) and if file size is larger than 0 bytes
276 | //
277 | if ( dwDataFileOffset && dwDataFileOffset < m_dwFileSize && pData->dwSize > 0 )
278 | {
279 | //
280 | // try X Ray on that buffer
281 | //
282 | ui64Key = 0;
283 |
284 | if ( XRayBuffer(static_cast(m_pBuffer + dwDataFileOffset), pData->dwSize, ui64Key) )
285 | {
286 | //
287 | // call callback function
288 | //
289 | memset( &XRayInfo, 0, sizeof(XRayInformation) );
290 |
291 | XRayInfo.lpType = lpEntry1;
292 | XRayInfo.lpName = lpEntry2;
293 | XRayInfo.lpLanguage = lpEntry3;
294 | XRayInfo.lpDataEntry = pData;
295 | XRayInfo.dwFileOffset = dwDataFileOffset;
296 | XRayInfo.ui64EncryptionKey = ui64Key;
297 |
298 | if ( m_lpCallback ) ((ResourceCallbackFunction)m_lpCallback)( static_cast(this), RM_XRAY, (LPVOID)lpEntry3, &XRayInfo );
299 |
300 | fFound = TRUE;
301 | }
302 | }
303 | }
304 | }
305 | }
306 | return fFound ? TRUE : FALSE;
307 | }
308 |
309 | BOOL CResourceParser::SearchEncryptionKey( BYTE* pBuffer, DWORD dwSize, UINT64 ui64SearchMask, UINT64 &ui64Key, UINT8 unKeySize )
310 | {
311 | UINT64 ui64DecryptKey = 0;
312 | DWORD dwRevertBytes = 0;
313 | BOOL fResult = FALSE;
314 |
315 | ui64Key = 0;
316 |
317 | //
318 | // get decryption key
319 | //
320 | if (unKeySize == 4)
321 | {
322 | ui64DecryptKey = *(DWORD*)(pBuffer) ^ (DWORD)ui64SearchMask;
323 | }
324 | else if (unKeySize == 8)
325 | {
326 | ui64DecryptKey = *(UINT64*)(pBuffer) ^ (UINT64)ui64SearchMask;
327 | }
328 |
329 | //
330 | // decrypt the whole buffer
331 | //
332 | __try
333 | {
334 | for ( DWORD n = 0; n < dwSize; n += unKeySize )
335 | {
336 | if (unKeySize == 4)
337 | {
338 | *(DWORD*)(pBuffer + n) ^= (DWORD)ui64DecryptKey;
339 | }
340 | else if ( unKeySize == 8)
341 | {
342 | *(UINT64*)(pBuffer + n) ^= (UINT64)ui64DecryptKey;
343 | }
344 | dwRevertBytes += unKeySize;
345 | }
346 | }
347 | __except( 1 )
348 | {
349 | // error while writing in buffer
350 | }
351 |
352 | //
353 | // check if its a valid PE file ( DOS + NT Headers + offset calculation from EP )
354 | //
355 | if ( IsValidPEInBuffer(pBuffer, dwRevertBytes) )
356 | {
357 | ui64Key = ui64DecryptKey;
358 | fResult = TRUE;
359 | }
360 | else
361 | {
362 | //
363 | // revert
364 | //
365 | for ( DWORD n = 0; n < dwRevertBytes; n += unKeySize )
366 | {
367 | switch ( unKeySize )
368 | {
369 | case 4:
370 | *(DWORD*)(pBuffer + n) ^= (DWORD)ui64DecryptKey;
371 | break;
372 | case 8:
373 | *(UINT64*)(pBuffer + n) ^= (UINT64)ui64DecryptKey;
374 | break;
375 | default:
376 | break;
377 | }
378 | }
379 | }
380 | return fResult;
381 | }
382 |
383 | BOOL CResourceParser::XRayBuffer( BYTE* pBuffer, DWORD dwSize, UINT64& ui64Key )
384 | {
385 | if ( pBuffer == NULL || dwSize == 0 )
386 | return FALSE;
387 |
388 | //
389 | // check if its a valid PE file
390 | //
391 | if ( IsValidPEInBuffer(pBuffer, dwSize) )
392 | return TRUE;
393 |
394 | //
395 | // Encrypt buffer
396 | //
397 | for ( unsigned int n = 0; n < sizeof(g_SearchInfoArray) / sizeof(g_SearchInfoArray[0]); n++ )
398 | {
399 | if ( SearchEncryptionKey(pBuffer, dwSize, g_SearchInfoArray[n].ui64SearchMask, ui64Key, g_SearchInfoArray[n].unKeySize) )
400 | return TRUE;
401 | }
402 |
403 | return FALSE;
404 | }
405 |
406 |
407 | ////
408 | //// search for entries
409 | //// lpResRoot = Root Resource Directory
410 | //// lpEntry = Current Entry
411 | //// lpSearch = Search Name or ID
412 | ////
413 | //BOOL CResourceParser::FindEntry( ResourceDirectoryTable *lpResRoot, ResourceDirectoryEntry *lpEntry, LPWSTR lpSearch )
414 | //{
415 | // WCHAR *lpName;
416 | // WORD nLength;
417 | // BOOL fResult = FALSE;
418 | //
419 | // //
420 | // // search by ID
421 | // //
422 | // if ( IS_INTRESOURCE( lpSearch ) )
423 | // {
424 | // if ( IS_INTRESOURCE( lpEntry->nIntegerID ) )
425 | // {
426 | // if ( (INT32)lpSearch == lpEntry->nIntegerID )
427 | // {
428 | // fResult = TRUE;
429 | // }
430 | // }
431 | // }
432 | // else
433 | // {
434 | // //
435 | // // search by Name
436 | // //
437 | // if ( !IS_INTRESOURCE( lpEntry->nIntegerID ) )
438 | // {
439 | // nLength = *(WORD*)((const char*)lpResRoot + (lpEntry->dwNameRva & 0x7FFFFFFF));
440 | // lpName = (WCHAR*)((const char*)lpResRoot + (lpEntry->dwNameRva & 0x7FFFFFFF) + sizeof(WORD));
441 | //
442 | // if ( _wcsnicmp( lpName, lpSearch, nLength ) == 0 )
443 | // {
444 | // fResult = TRUE;
445 | // }
446 | // }
447 | // }
448 | // return fResult;
449 | //}
450 | //
451 | //
452 | ///*
453 | // lpType = Type of resource
454 | // lpName = Name of resource
455 | // nLanguage = Language ID, use -1 if you want to have the first language entry.
456 | //*/
457 | //BOOL CResourceParser::FindResource( LPWSTR lpType, LPWSTR lpName, WORD wLanguage, DWORD64& dwOffset, DWORD& dwSize )
458 | //{
459 | // DWORD64 dwResourceFileOffset = 0, dwResourceVA = 0, dwResourceSize = 0;
460 | //
461 | // ResourceDirectoryTable *lpResRoot, *lpResType, *lpResName;
462 | // ResourceDirectoryEntry *lpEntry1, *lpEntry2, *lpEntry3;
463 | // ResourceDataEntry *pData;
464 | //
465 | // BOOL fFoundDirectory = FALSE;
466 | //
467 | // if ( !m_pBuffer || !m_NtHeader )
468 | // return FALSE;
469 | //
470 | // //
471 | // // check if we have a valid PE file with a resource section
472 | // //
473 | // dwResourceVA = m_NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
474 | // dwResourceSize = m_NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
475 | //
476 | // if ( dwResourceSize == 0 || dwResourceVA == 0 )
477 | // return FALSE;
478 | //
479 | // //
480 | // // get resource section
481 | // //
482 | // dwResourceFileOffset = RvaToFileOffset( dwResourceVA );
483 | // if ( dwResourceFileOffset == (DWORD64)-1 )
484 | // return FALSE;
485 | //
486 | // lpResRoot = (ResourceDirectoryTable *)( m_pBuffer + dwResourceFileOffset );
487 | // if ( lpResRoot->dwCharacteristics != 0 )
488 | // return FALSE;
489 | //
490 | // //
491 | // // enumerate all types
492 | // //
493 | // for ( WORD i = 0; i < lpResRoot->dwNumberOfIDEntries + lpResRoot->dwNumberOfNameEntries; i++)
494 | // {
495 | // lpEntry1 = (ResourceDirectoryEntry *) (lpResRoot + 1) + i;
496 | // if ( (lpEntry1->dwDataRva & 0x7FFFFFFF) >= dwResourceSize )
497 | // return FALSE;
498 | //
499 | // lpResType = (ResourceDirectoryTable *) ((const char*)lpResRoot + (lpEntry1->dwDataRva & 0x7FFFFFFF));
500 | // if ( !lpResType )
501 | // return FALSE;
502 | //
503 | // if ( !FindEntry( lpResRoot, lpEntry1, lpType ) )
504 | // continue;
505 | //
506 | // //
507 | // // enumerate all names
508 | // //
509 | // for ( WORD j = 0; j < lpResType->dwNumberOfIDEntries + lpResType->dwNumberOfNameEntries; j++ )
510 | // {
511 | // lpEntry2 = (ResourceDirectoryEntry *) (lpResType + 1) + j;
512 | // if ( !lpEntry2 || (lpEntry2->dwDataRva & 0x7FFFFFFF) >= dwResourceSize )
513 | // return FALSE;
514 | //
515 | // lpResName = (ResourceDirectoryTable *) ((const char*)lpResRoot + (lpEntry2->dwDataRva & 0x7FFFFFFF));
516 | // if ( !lpResName )
517 | // return FALSE;
518 | //
519 | // if ( !FindEntry( lpResRoot, lpEntry2, lpName ) )
520 | // continue;
521 | //
522 | // //
523 | // // enumerate all languages
524 | // // now we have access to the offsets of the data
525 | // //
526 | // for ( WORD k = 0; k < lpResName->dwNumberOfIDEntries + lpResName->dwNumberOfNameEntries; k++ )
527 | // {
528 | // lpEntry3 = (ResourceDirectoryEntry *) (lpResName +1) + k;
529 | // if ( (lpEntry3->dwDataRva & 0x7FFFFFFF) >= dwResourceSize )
530 | // return FALSE;
531 | //
532 | // if ( wLanguage != (WORD)-1 )
533 | // {
534 | // if ( !FindEntry( lpResRoot, lpEntry3, (LPWSTR)wLanguage ) )
535 | // continue;
536 | // }
537 | //
538 | // pData = (ResourceDataEntry *) ((const char*)lpResRoot + (lpEntry3->dwDataRva & 0x7FFFFFFF));
539 | // dwOffset = RvaToFileOffset( pData->dwDataRva );
540 | // if ( dwOffset == (DWORD64)-1 || pData->dwSize == 0 )
541 | // return FALSE;
542 | //
543 | // dwSize = pData->dwSize;
544 | //
545 | // return TRUE;
546 | // }
547 | // }
548 | // }
549 | // return FALSE;
550 | //}
551 | //
552 |
--------------------------------------------------------------------------------
/MalwareResourceScanner_Console/ResourceParser.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "windows.h"
3 |
4 | enum ResourceCallbackNames{ RM_ENUM_TYPE = 0, RM_ENUM_NAME, RM_ENUM_LANG, RM_XRAY, RM_ENUM_RESOURCE};
5 |
6 | struct ResourceDirectoryTable
7 | {
8 | DWORD dwCharacteristics;
9 | DWORD dwTimeDateStamp;
10 | WORD dwMajorVersion;
11 | WORD dwMinorVersion;
12 | WORD dwNumberOfNameEntries;
13 | WORD dwNumberOfIDEntries;
14 | };
15 |
16 | struct ResourceDirectoryEntry
17 | {
18 | union
19 | {
20 | DWORD dwNameRva; // address of the string that gives the Type, Name or Language ID entry (table level dependent)
21 | INT32 nIntegerID; // the integer that identifies the Type, Name or Language ID entry
22 | };
23 | union
24 | {
25 | DWORD dwDataRva; // high bit = 0, address of the resource data within the resource section(leaf)
26 | DWORD dwSubDirectoryRva; // high bit = 1, the lower 31 bits are the address of another resource directory table (one level down)
27 | };
28 | };
29 |
30 | struct ResourceDataEntry
31 | {
32 | DWORD dwDataRva;
33 | DWORD dwSize;
34 | DWORD dwCodePage;
35 | DWORD dwReserved;
36 | };
37 |
38 | struct XRayInformation
39 | {
40 | ResourceDataEntry *lpDataEntry;
41 | ResourceDirectoryEntry *lpType;
42 | ResourceDirectoryEntry *lpName;
43 | ResourceDirectoryEntry *lpLanguage;
44 | DWORD64 dwFileOffset;
45 | UINT64 ui64EncryptionKey;
46 | };
47 |
48 | #define LODWORD(l) ((DWORD)(l & 0x00000000ffffffff))
49 | #define HIDWORD(l) ((DWORD)(( l >> 32) & 0x00000000ffffffff))
50 |
51 | typedef DWORD (WINAPI * ResourceCallbackFunction) ( LPVOID lpObject, DWORD dwMessage, LPVOID lpEntry, LPVOID lpParam1 );
52 |
53 |
54 | struct SearchInfo
55 | {
56 | UINT64 ui64SearchMask;
57 | UINT8 unKeySize;
58 | };
59 |
60 | const SearchInfo g_SearchInfoArray[] =
61 | {
62 | {0x00505a4d, 4}, // Delphi
63 | {0x00905a4d, 4}, // C / Assembler
64 | {0x00005a4d, 4},
65 | {0x0000000200505a4d, 8},
66 | {0x0000000300505a4d, 8},
67 | {0x0000000000505a4d, 8}
68 | };
69 |
70 |
71 | class CResourceParser
72 | {
73 | BYTE* m_pBuffer;
74 | DWORD m_dwFileSize;
75 |
76 | WCHAR m_szFileName[ MAX_PATH + 1 ];
77 |
78 | PIMAGE_DOS_HEADER m_DosHeader;
79 | PIMAGE_NT_HEADERS32 m_NtHeader;
80 | PIMAGE_NT_HEADERS64 m_NtHeader64;
81 | BOOL m_fPePlus;
82 | BOOL m_fDumpFile;
83 | DWORD m_dwDumpNumber;
84 |
85 | ResourceCallbackFunction *m_lpCallback;
86 |
87 | private:
88 | BOOL ReadHeaders();
89 | BOOL SearchEncryptionKey( BYTE* pBuffer, DWORD dwSize, UINT64 unSearchMask, UINT64& unKey, UINT8 unKeySize );
90 | BOOL IsValidPEInBuffer( const BYTE* pBuffer, DWORD dwSize );
91 | //BOOL FindEntry( ResourceDirectoryTable* lpResRoot, ResourceDirectoryEntry* pEntry, LPWSTR lpSearch );
92 |
93 | public:
94 | CResourceParser()
95 | {
96 | m_pBuffer = NULL;
97 | m_lpCallback = NULL;
98 | m_fDumpFile = FALSE;
99 | memset( m_szFileName, 0, sizeof(m_szFileName) );
100 | m_dwDumpNumber = 0;
101 | m_DosHeader = NULL;
102 | m_NtHeader = NULL;
103 | m_NtHeader64 = NULL;
104 | m_dwFileSize = 0;
105 | m_fPePlus = FALSE;
106 | }
107 | ~CResourceParser() { delete[] m_pBuffer; };
108 | BOOL LoadFile( LPCWSTR szFileName );
109 | DWORD64 RvaToFileOffset( DWORD64 dwRVA );
110 | DWORD64 RvaToFileOffset( DWORD64 dwRVA, const BYTE* pBuffer, WORD wNumberOfSections, BOOL fPePlus );
111 | BOOL ParseResources( );
112 | //BOOL FindResource( LPWSTR lpType, LPWSTR lpName, WORD nLanguage, DWORD64& wOffset, DWORD& dwSize );
113 | BOOL XRayBuffer( BYTE* pBuffer, DWORD dwSize, UINT64& unKey );
114 |
115 | //
116 | // class
117 | //
118 | void SetCallback( ResourceCallbackFunction* lpCallback ) { m_lpCallback = lpCallback; };
119 | BYTE* GetBuffer() { return m_pBuffer; };
120 | DWORD GetSize() { return m_dwFileSize; };
121 | void SetDumpFlag( BOOL fDumpFile ) { m_fDumpFile = fDumpFile; };
122 | BOOL GetDumpFlag() const { return m_fDumpFile; };
123 | WCHAR* GetFileName() { return m_szFileName; };
124 | DWORD GetDumpNumber() const { return m_dwDumpNumber; };
125 | void IncrementDumpNumber() { m_dwDumpNumber++; };
126 | };
127 |
128 |
--------------------------------------------------------------------------------
/MalwareResourceScanner_Console/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "ResourceParser.h"
6 |
7 | //void ShowLastError()
8 | //{
9 | // DWORD dwLastError;
10 | // LPWSTR szMsgBuffer = NULL;
11 | //
12 | // dwLastError = GetLastError();
13 | //
14 | // FormatMessageW(
15 | // FORMAT_MESSAGE_ALLOCATE_BUFFER |
16 | // FORMAT_MESSAGE_FROM_SYSTEM |
17 | // FORMAT_MESSAGE_IGNORE_INSERTS,
18 | // NULL,
19 | // dwLastError,
20 | // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
21 | // szMsgBuffer,
22 | // 0, NULL
23 | // );
24 | //
25 | // printf( "ERROR: %08x ( %08d )\nMESSAGE: %S\n", dwLastError, dwLastError, szMsgBuffer );
26 | //}
27 |
28 | struct RegistryScanInfo
29 | {
30 | HKEY hKey;
31 | WCHAR *szPath;
32 | };
33 |
34 | BOOL DumpBufferToFile( LPWSTR szName, BYTE* lpBuffer, DWORD dwSize )
35 | {
36 | HANDLE hFile;
37 | DWORD dwNumberOfBytesWritten = 0;
38 | BOOL fResult = FALSE;
39 |
40 | hFile = CreateFileW( szName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
41 | if ( hFile != INVALID_HANDLE_VALUE )
42 | {
43 | if ( WriteFile( hFile, lpBuffer, dwSize, &dwNumberOfBytesWritten, NULL ) && dwNumberOfBytesWritten == dwSize )
44 | {
45 | fResult = TRUE;
46 | }
47 | CloseHandle( hFile );
48 | }
49 | return fResult;
50 | }
51 |
52 | DWORD WINAPI MyResourcesCallback ( LPVOID lpObject, DWORD dwMessage, LPVOID lpEntry, LPVOID lpParam1 )
53 | {
54 | CResourceParser *pFile = static_cast(lpObject);
55 | //ResourceDirectoryEntry *pEntry = (ResourceDirectoryEntry*)lpEntry;
56 | XRayInformation *lpInformation = NULL;
57 | BYTE* pAddress = NULL;
58 | WCHAR szName[ MAX_PATH ] = { 0 };
59 |
60 | switch ( dwMessage )
61 | {
62 | case RM_XRAY:
63 | //
64 | // Message 3 is that we have found a PE file in the resource directory.
65 | //
66 | lpInformation = static_cast(lpParam1);
67 |
68 | pAddress = (BYTE*)(pFile->GetBuffer() + lpInformation->dwFileOffset);
69 |
70 | printf( "Filename: %S\n"
71 | " Type: 0x%08x, Name: 0x%08x, Language: 0x%08x\n"
72 | " Offset: 0x%08llx, Size: 0x%08x, Encryption Key: 0x%08llx\n\n",
73 | pFile->GetFileName(),
74 | lpInformation->lpType ? lpInformation->lpType->nIntegerID : 0,
75 | lpInformation->lpName ? lpInformation->lpName->nIntegerID : 0,
76 | lpInformation->lpLanguage ? lpInformation->lpLanguage->nIntegerID : 0,
77 | lpInformation->dwFileOffset,
78 | lpInformation->lpDataEntry ? lpInformation->lpDataEntry->dwSize : 0,
79 | lpInformation->ui64EncryptionKey);
80 |
81 | //
82 | // dump file
83 | //
84 | if ( pFile->GetDumpFlag() && lpInformation && lpInformation->lpDataEntry )
85 | {
86 | swprintf_s( szName, MAX_PATH, L"%s_%lu.bin", pFile->GetFileName(), pFile->GetDumpNumber() );
87 |
88 | if ( !DumpBufferToFile( szName, pAddress, lpInformation->lpDataEntry->dwSize ) )
89 | {
90 | printf( " Can't dump to file! (Last Error : %08d d)\n\n", GetLastError() );
91 | }
92 | else
93 | {
94 | printf( " Resource saved to: %S\n\n", szName );
95 | pFile->IncrementDumpNumber();
96 | }
97 | }
98 | break;
99 | }
100 | return 0;
101 | }
102 |
103 |
104 | BOOL ScanFile( CResourceParser &pFile, LPWSTR lpszFileName, BOOL fScanNonPeFiles )
105 | {
106 | BOOL fResult = FALSE;
107 | if ( pFile.LoadFile(lpszFileName) )
108 | {
109 | fResult = pFile.ParseResources();
110 | }
111 | else if ( fScanNonPeFiles )
112 | {
113 | UINT64 ui64Key = 0;
114 | pFile.LoadFile(lpszFileName);
115 | fResult = pFile.XRayBuffer( pFile.GetBuffer(), pFile.GetSize(), ui64Key );
116 | if ( fResult )
117 | {
118 | XRayInformation info = { 0 };
119 | ResourceDataEntry entry = { 0 };
120 | info.ui64EncryptionKey = ui64Key;
121 | entry.dwSize = pFile.GetSize();
122 | info.lpDataEntry = &entry;
123 | MyResourcesCallback( (LPVOID)&pFile, RM_XRAY, NULL, (LPVOID)&info );
124 | }
125 | }
126 |
127 | return fResult;
128 | }
129 |
130 | BOOL ScanDirectory( CResourceParser &pFile, LPWSTR lpszDirectory, BOOL fScanNonPeFiles )
131 | {
132 | WCHAR szSearchFilter[ MAX_PATH + 1];
133 | WCHAR szFullPath[ MAX_PATH + 1];
134 | WIN32_FIND_DATAW fdFileData = { 0 };
135 | HANDLE hSearch;
136 | BOOL fResult = FALSE;
137 | DWORD dwAttributes;
138 |
139 | StringCchPrintf( szSearchFilter, MAX_PATH, L"%s\\*.*", lpszDirectory, fdFileData.cFileName);
140 |
141 | hSearch = FindFirstFileW( szSearchFilter, &fdFileData );
142 |
143 | if ( hSearch != INVALID_HANDLE_VALUE )
144 | {
145 | do
146 | {
147 | if ( wcscmp( fdFileData.cFileName, L"." ) == 0 || wcscmp( fdFileData.cFileName, L".." ) == 0 )
148 | continue;
149 |
150 | StringCchPrintf( szFullPath, MAX_PATH, L"%s\\%s", lpszDirectory, fdFileData.cFileName);
151 |
152 | dwAttributes = GetFileAttributesW(szFullPath);
153 | if ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY )
154 | {
155 | ScanDirectory(pFile, szFullPath, fScanNonPeFiles );
156 | }
157 | else
158 | {
159 | ScanFile( pFile, szFullPath, fScanNonPeFiles );
160 | }
161 | } while ( FindNextFileW( hSearch, &fdFileData ) );
162 | }
163 |
164 | return fResult;
165 | }
166 |
167 | BOOL FileExists( LPWSTR lpszFileName )
168 | {
169 | HANDLE hFile;
170 |
171 | hFile = CreateFileW( lpszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
172 | if ( hFile != INVALID_HANDLE_VALUE )
173 | {
174 | CloseHandle( hFile );
175 | return TRUE;
176 | }
177 | return FALSE;
178 | }
179 |
180 |
181 | LPWSTR ExtractFileNameFromRegValue( LPCWSTR lpszSrc, DWORD dwSize, LPWSTR lpszDestinationPath )
182 | {
183 | WCHAR *szPos = NULL;
184 | WCHAR *szSpace = NULL;
185 | LPWSTR lpszDestination;
186 |
187 | lpszDestination = lpszDestinationPath;
188 |
189 | if ( !lpszSrc || !lpszDestination )
190 | return NULL;
191 |
192 | wcsncpy_s( lpszDestination, dwSize, lpszSrc, dwSize );
193 |
194 | //
195 | // If first character is a " we will ignore it
196 | //
197 | if ( *lpszDestination == '"' )
198 | {
199 | lpszDestination += 1;
200 | szPos = wcschr( lpszDestination, '"' );
201 | if ( szPos )
202 | {
203 | *szPos = '\0';
204 | }
205 | }
206 |
207 | //
208 | // Check if path starts with rundll32
209 | //
210 | if ( _wcsnicmp( lpszDestination, L"rundll32", 8 ) == 0 )
211 | {
212 | szPos = wcschr( lpszDestination, ' ' );
213 | if ( szPos )
214 | {
215 | lpszDestination = (szPos + 1);
216 | szPos = wcschr( lpszDestination, ',' );
217 | if ( szPos )
218 | {
219 | *szPos = '\0';
220 | }
221 | }
222 | }
223 |
224 | //
225 | // Remove arguments after path
226 | //
227 | szPos = wcsrchr( lpszDestination, L'.' );
228 | szSpace = wcsrchr( lpszDestination, L' ' );
229 | if ( szSpace > szPos )
230 | *szSpace = '\0';
231 |
232 | //
233 | // lets see if it starts with an c:\ or something, else we will attach a C:\WINDOWS\ or C:\WINDOWS\SYSTEM32\
234 | //
235 | if ( FileExists(lpszDestination) )
236 | return lpszDestination;
237 |
238 | wchar_t szTemp[ MAX_PATH +1 ];
239 | wchar_t szTempDir[ MAX_PATH +1 ];
240 |
241 | GetWindowsDirectoryW(szTempDir, MAX_PATH );
242 | StringCchPrintf(szTemp, MAX_PATH, L"%s\\%s", szTempDir, lpszDestination);
243 |
244 | if ( FileExists(szTemp) )
245 | {
246 | wcsncpy_s( lpszDestinationPath, MAX_PATH, szTemp, MAX_PATH );
247 | return lpszDestinationPath;
248 | }
249 |
250 | GetSystemDirectoryW(szTempDir, MAX_PATH );
251 | StringCchPrintf(szTemp, MAX_PATH, L"%s\\%s", szTempDir, lpszDestination);
252 |
253 | if ( FileExists(szTemp) )
254 | {
255 | wcsncpy_s(lpszDestinationPath, dwSize, szTemp, MAX_PATH );
256 | return lpszDestinationPath;
257 | }
258 |
259 | return NULL;
260 |
261 | }
262 |
263 | BOOL ScanQuickRegistry( CResourceParser &pFile )
264 | {
265 | BOOL fResult = FALSE;
266 | HKEY hReg = NULL;
267 | DWORD dwDisposion = 0;
268 | WCHAR szValueName[ MAX_PATH +1 ] = { 0 };
269 | DWORD dwIndex = 0;
270 | DWORD dwValueNameSize = 0;
271 | DWORD dwType = 0;
272 | BYTE lpData[ 0x800 ] = { 0 };
273 | WCHAR szDestinationFilePath[ MAX_PATH + 1 ] = { 0 };
274 | WCHAR *lpszScanPath = NULL;
275 | DWORD dwFilePathSize = 0;
276 | DWORD dwDataSize = 0;
277 | DWORD dwResult = 0;
278 |
279 | RegistryScanInfo RegistryKeys[] = {
280 | { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run" },
281 | { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce" },
282 | { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices" },
283 | { HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run" },
284 | { HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce" },
285 | { HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices" },
286 | { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Userinit" },
287 | { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell" },
288 | { HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Known DLLs" },
289 | { HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SharedTaskScheduler" }
290 | };
291 |
292 | printf( "* Registry Quick Scan\n" );
293 |
294 | dwDisposion = REG_OPENED_EXISTING_KEY;
295 | for ( int n = 0; n < sizeof(RegistryKeys) / sizeof(RegistryKeys[0]); n++ )
296 | {
297 | if ( RegCreateKeyExW( RegistryKeys[n].hKey, RegistryKeys[n].szPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, NULL, &hReg, &dwDisposion ) == ERROR_SUCCESS )
298 | {
299 | dwIndex = 0;
300 | while ( TRUE )
301 | {
302 | dwDataSize = sizeof(lpData);
303 | dwValueNameSize = MAX_PATH;
304 | dwType = REG_SZ;
305 | dwResult = RegEnumValueW( hReg, dwIndex, szValueName, &dwValueNameSize, NULL, &dwType, lpData, &dwDataSize );
306 | if ( dwResult == ERROR_SUCCESS )
307 | {
308 | if ( lpData && *lpData )
309 | {
310 | dwFilePathSize = MAX_PATH;
311 | lpszScanPath = ExtractFileNameFromRegValue( (LPCWSTR)lpData, dwFilePathSize, szDestinationFilePath );
312 | if ( lpszScanPath )
313 | {
314 | ScanFile( pFile, (LPWSTR)lpszScanPath, FALSE );
315 | }
316 | }
317 | dwIndex++;
318 | }
319 | else
320 | {
321 | //
322 | // some error occurred or we have scanned all items
323 | //
324 | if ( dwResult != ERROR_NO_MORE_ITEMS )
325 | {
326 | continue;
327 | }
328 | break;
329 | }
330 | }
331 | RegCloseKey( hReg );
332 | }
333 | }
334 |
335 | //hRegistry = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
336 |
337 | return fResult;
338 | }
339 |
340 | void ShowInfo()
341 | {
342 | printf( "Usage:\n" );
343 | printf( "mrs.exe \n");
344 | printf( " -d Scans directory\n");
345 | printf( " -unpack Auto unpack found files\n" );
346 | printf( " -quickscan Quick-Scan Windows start up programs\n" );
347 | printf( " -scannonpefiles Try to unpack also non-PE files (like unknown file formats)\n" );
348 | printf( "\n\n" );
349 | }
350 |
351 | int wmain(int argc, wchar_t * argv[] )
352 | {
353 | CResourceParser ResourceParser;
354 | BOOL fDirectory = FALSE;
355 | BOOL fInvalidParameter = FALSE;
356 | BOOL fQuickScan = FALSE;
357 | LPWSTR szScanPath = NULL;
358 | BOOL fScanNonPeFiles = FALSE;
359 |
360 | printf( "Malware Resource Scanner v0.1 by Esmid Idrizovic\n" );
361 | printf( "27. October 2011\n\n" );
362 |
363 | if ( argc < 2 )
364 | {
365 | ShowInfo();
366 | return 0;
367 | }
368 |
369 | ResourceParser.SetCallback( (ResourceCallbackFunction*)&MyResourcesCallback );
370 |
371 | for ( int n = 1; n < argc; n++ )
372 | {
373 | if ( _wcsicmp(argv[n], L"-unpack") == 0 )
374 | {
375 | ResourceParser.SetDumpFlag( TRUE );
376 | }
377 | else if ( _wcsicmp(argv[n], L"-d") == 0 )
378 | {
379 | if ( (n + 1) < argc )
380 | {
381 | fDirectory = TRUE;
382 | }
383 | else
384 | {
385 | fInvalidParameter = TRUE;
386 | break;
387 | }
388 | }
389 | else if ( _wcsicmp(argv[n], L"-scannonpefiles") == 0 )
390 | {
391 | fScanNonPeFiles = TRUE;
392 | }
393 | else if ( _wcsicmp(argv[n], L"-quickscan") == 0 )
394 | {
395 | fQuickScan = TRUE;
396 | }
397 | else
398 | {
399 | if ( argv[n] )
400 | szScanPath = argv[n];
401 | }
402 | }
403 |
404 | if ( fInvalidParameter || (!fQuickScan && !szScanPath) )
405 | {
406 | ShowInfo();
407 | }
408 | else if ( fQuickScan )
409 | {
410 | ScanQuickRegistry( ResourceParser );
411 | }
412 | else if ( szScanPath)
413 | {
414 | if ( fDirectory )
415 | {
416 | ScanDirectory( ResourceParser, szScanPath, fScanNonPeFiles );
417 | }
418 | else
419 | {
420 | ScanFile( ResourceParser, szScanPath, fScanNonPeFiles );
421 | }
422 | }
423 |
424 | return 0;
425 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Malware Resource Scanner
2 | =======================
3 | Malware Resource Scanner can identify PE files which are hidden in other PE file resources which are encrypted by an XOR key (up to an 8 Byte key). You can scan single files and you can also scan a directory and automatically unpack found hidden PE files. If MSR can't detect your hidden PE file then you must update the g_SearchInfoArray in ResourceParser.h.
4 |
5 | Usage
6 | =====
7 | Malware Resource Scanner v0.1 by Esmid Idrizovic
8 | 27. October 2011
9 |
10 | Usage:
11 | mrs.exe
12 | -d Scans directory
13 | -unpack Auto unpack found files
14 | -quickscan Quick-Scan Windows start up programs
15 | -scannonpefiles Try to unpack also non-PE files (like unknown file formats)
16 |
17 |
--------------------------------------------------------------------------------
/tests/notepad32.exe_:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edix/MalwareResourceScanner/fa6e70e493e2a83a41a43101863513a33fd57ce3/tests/notepad32.exe_
--------------------------------------------------------------------------------
/tests/notepad64.exe_:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edix/MalwareResourceScanner/fa6e70e493e2a83a41a43101863513a33fd57ce3/tests/notepad64.exe_
--------------------------------------------------------------------------------
/tests/xored1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edix/MalwareResourceScanner/fa6e70e493e2a83a41a43101863513a33fd57ce3/tests/xored1
--------------------------------------------------------------------------------
/tests/xored2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edix/MalwareResourceScanner/fa6e70e493e2a83a41a43101863513a33fd57ce3/tests/xored2
--------------------------------------------------------------------------------
/tests/xored3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edix/MalwareResourceScanner/fa6e70e493e2a83a41a43101863513a33fd57ce3/tests/xored3
--------------------------------------------------------------------------------
/tests/xored4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edix/MalwareResourceScanner/fa6e70e493e2a83a41a43101863513a33fd57ce3/tests/xored4
--------------------------------------------------------------------------------
/tests/xored5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edix/MalwareResourceScanner/fa6e70e493e2a83a41a43101863513a33fd57ce3/tests/xored5
--------------------------------------------------------------------------------
/tool/MalwareResourceScanner_Console.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edix/MalwareResourceScanner/fa6e70e493e2a83a41a43101863513a33fd57ce3/tool/MalwareResourceScanner_Console.exe
--------------------------------------------------------------------------------