root/pehunter/pehunter.c

Revision 1148, 7.2 kB (checked in by till, 1 year ago)

some robustness...

Line 
1 /*
2  * pehunter.c
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * Copyright (C) 2007 Tillmann Werner <tillmann.werner@gmx.de>
19  */
20
21 #include <unistd.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include "sf_snort_plugin_api.h"
26 #include "sf_snort_packet.h"
27 #include "debug.h"
28
29 #include "pehunter.h"
30 #include "md5.h"
31
32 #include "profiler.h"
33 #ifdef PERF_PROFILING
34 PreprocStats pehuntPerfStats;
35 PreprocStats pehuntDetectPerfStats;
36 int pehuntDetectCalled = 0;
37 #endif
38
39
40 extern DynamicPreprocessorData _dpd;
41
42 SessionData *_pehunt;
43
44
45 static void PEHunter_SessionFree(void * v)
46 {
47         SessionData *sdata = (SessionData *) v;
48
49         if (sdata)
50         {
51                 if ( sdata->data ) free(sdata->data);
52                 free(sdata);
53         }
54         return;
55 }
56
57
58
59 SessionData *PEHunter_Setup(SFSnortPacket *p)
60 {
61         SessionData *datap = NULL;
62
63         if (( !p ) || ( !p->stream_session_ptr )) return(NULL);
64         if ( !_dpd.streamAPI )
65         {
66                 DEBUG_WRAP(_dpd.debugMsg(DEBUG_PEHUNTER, "Error: Failed to get Stream API - Stream not enabled?\n"););
67                 return(NULL);
68         }
69
70         /* Get session pointer */
71         if (( datap = _dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_PEHUNTER)) == NULL)
72         {
73                 if ((datap = (SessionData *) malloc(sizeof(SessionData))) == NULL)
74                 {
75                         _dpd.fatalMsg("%s(%d) => Failed to allocate memory for session data\n");
76                         return(NULL);
77                 }
78
79                 /* Initialize state for first packet */
80                 bzero(datap, sizeof(SessionData));
81                 _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_PEHUNTER, datap, &PEHunter_SessionFree);
82         }
83
84         return(datap);
85 }
86
87 /*
88  * Function: Hunt()
89  *
90  * Purpose: Search for PE magic byte sequence in stream,
91  * locate PE header, extract length and dump extracted PE into a file
92  *
93  * Arguments: Snort packet.
94  *
95  * Returns: void
96  *
97  */
98 int Hunt(SFSnortPacket *p)
99 {
100         int                     retval;
101         u_int32_t               parsedBytes, dosOffset, maxOffset, maxLen, i, parseStart, pos;
102         IMAGE_DOS_HEADER        *dosHeader;
103         IMAGE_NT_HEADERS32      *peHeader;
104         IMAGE_SECTION_HEADER    *sectHeader;
105         SessionData             *session_data;
106         const char              *dh_sig = "MZ";
107         char                    *filename;
108         FILE                    *dumpfile;
109         PROFILE_VARS;
110
111         dumpfile        = NULL;
112         filename        = NULL;
113         session_data    = NULL;
114         parsedBytes     = 0;
115         maxOffset       = 0;
116         maxLen          = 0;
117
118         /* ignore if no data */
119         if (( !p->payload ) || ( !p->payload_size ))
120         {
121                 return(0);
122         }
123
124         if ( (session_data = PEHunter_Setup(p)) == NULL)
125         {
126                 /* Could not get/create the session data for this packet. */
127                 PREPROC_PROFILE_END(pehuntPerfStats);
128                 return(0);
129         }
130
131         if (session_data->dumped)
132         {
133                 /* file already extracted */
134                 return(1);
135         }
136        
137         /* Append payload to session data */
138         if ((session_data->data = (u_char *) realloc(session_data->data, session_data->len + p->payload_size)) == NULL)
139         {
140                 _dpd.fatalMsg("%s(%d) => Failed to allocate memory for session data\n");
141                 return(0);
142         }
143
144         parseStart = (session_data->len ? (session_data->len-1) : 0);
145         memcpy(session_data->data + session_data->len, p->payload, p->payload_size);
146         session_data->len += p->payload_size;
147
148         if (session_data->match && (session_data->len >= (session_data->matchpos + session_data->filelen)))
149         {
150                 /*
151                 if (chdir(_pehunterConfig.dumpDir) == -1)
152                 {
153                         _dpd.fatalMsg("%s(): Unable to change into %s: %s\n", __PRETTY_FUNCTION__, _pehunterConfig.dumpDir, strerror(errno));
154                 }
155                 */
156                 if ((filename = strdup(_pehunterConfig.dumpDir)) == NULL)
157                 {
158                         _dpd.fatalMsg("%s(): Unable to allocate memory: %s\n", __PRETTY_FUNCTION__, strerror(errno));
159                 }
160                 if ((filename = realloc(filename, strlen(filename)+34)) == NULL) {
161                         _dpd.fatalMsg("%s(): Unable to allocate memory: %s\n", __PRETTY_FUNCTION__, strerror(errno));
162                 }
163                
164                 /* assemble filename */
165                 bzero(filename+strlen(filename), 34);
166                 strncat(filename, "/", 1);
167                 mem_md5sum(session_data->data+session_data->matchpos, session_data->filelen);
168                 strncat(filename, mem_md5sum(session_data->data+session_data->matchpos, session_data->filelen), 32);
169
170                 if ((dumpfile = fopen(filename, "w")) == NULL)
171                 {
172                         _dpd.fatalMsg("%s(): Unable to open dumpfile %s: %s\n", __PRETTY_FUNCTION__, filename, strerror(errno));
173                 }
174                 if ((retval = fwrite(session_data->data+session_data->matchpos, 1, session_data->filelen, dumpfile)) < session_data->filelen)
175                 {
176                         _dpd.fatalMsg("%s(): Unable to write dumpfile %s (%u bytes written): %s\n", __PRETTY_FUNCTION__, filename, retval, strerror(errno));
177                 }
178                 if (fclose(dumpfile) == EOF)
179                 {
180                         _dpd.fatalMsg("%s(): Unable to close dumpfile %s: %s\n", __PRETTY_FUNCTION__, filename, strerror(errno));
181                 }
182                 session_data->dumped = 1;
183                 _dpd.logMsg("PE file extracted: %u bytes dumped to %s.\n", session_data->filelen, filename);
184                 free(filename);
185                
186                 return(1);
187         }
188
189
190          /* Check for DOS header signature */
191         for (dosOffset=parseStart; (dosOffset + strlen(dh_sig)) < session_data->len; dosOffset++)
192         {
193                 if (memcmp(session_data->data + dosOffset, dh_sig, strlen(dh_sig)) == 0) break;
194         }
195         parsedBytes = dosOffset - parseStart;
196
197         /* Spot DOS header */
198         if (session_data->len < (sizeof(IMAGE_DOS_HEADER) + parsedBytes)) return(0);
199         dosHeader = (IMAGE_DOS_HEADER *)(session_data->data + parsedBytes);
200         if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return(0);
201         pos = parsedBytes;
202         if (_pehunterConfig.debug) _dpd.logMsg("DOS header found at offset %lu.\n", pos);
203
204         if (session_data->len < (sizeof(IMAGE_NT_HEADERS32) + parsedBytes + dosHeader->e_lfanew)) return(0);
205         parsedBytes += dosHeader->e_lfanew;
206         if (_pehunterConfig.debug) _dpd.logMsg("DOS header e_lfanew is %lu, parsedBytes is %lu.\n", dosHeader->e_lfanew, parsedBytes);
207
208         /* image file header */
209         if ((session_data->len) < (sizeof(IMAGE_NT_HEADERS32) + parsedBytes)) return(0);
210         peHeader = (IMAGE_NT_HEADERS32*)(session_data->data + parsedBytes);
211         if (peHeader->Signature == IMAGE_NT_SIGNATURE)
212         {
213                 if (_pehunterConfig.debug) _dpd.logMsg("NT header found at offset %lu.\n", parsedBytes);
214                 parsedBytes += sizeof(IMAGE_NT_HEADERS32);
215
216                 /* loop through section table */
217                 for (i=0; i<peHeader->FileHeader.NumberOfSections; i++) {
218                         if (session_data->len < (sizeof(IMAGE_SECTION_HEADER) + parsedBytes)) return(0);
219                         sectHeader = (IMAGE_SECTION_HEADER *)(session_data->data + parsedBytes);
220                         if (_pehunterConfig.debug) _dpd.logMsg("Section header found at offset %lu.\n", parsedBytes);
221                         parsedBytes += sizeof(IMAGE_SECTION_HEADER);
222                         if (_pehunterConfig.debug) _dpd.logMsg("Section %lu (%s): starts at offset %lu (%u bytes)\n",
223                                 i, sectHeader->Name, sectHeader->PointerToRawData, sectHeader->SizeOfRawData);
224                         if (maxOffset < sectHeader->PointerToRawData) {
225                                 maxOffset       = sectHeader->PointerToRawData;
226                                 maxLen          = sectHeader->SizeOfRawData;
227                         }
228                 }
229         }
230         if (maxOffset + maxLen)
231         {
232                 session_data->match     = 1;
233                 session_data->matchpos  = pos;
234                 session_data->filelen   = maxOffset + maxLen;
235         }
236
237         return(0);
238 }
Note: See TracBrowser for help on using the browser.