|
|
|
|
@ -29,7 +29,6 @@
|
|
|
|
|
#include "detect.h"
|
|
|
|
|
#include "detect-engine.h"
|
|
|
|
|
#include "detect-parse.h"
|
|
|
|
|
#include "detect-content.h"
|
|
|
|
|
#include "detect-pcre.h"
|
|
|
|
|
#include "detect-isdataat.h"
|
|
|
|
|
#include "detect-bytetest.h"
|
|
|
|
|
@ -37,436 +36,14 @@
|
|
|
|
|
#include "detect-byte-extract.h"
|
|
|
|
|
#include "detect-engine-content-inspection.h"
|
|
|
|
|
|
|
|
|
|
#include "util-spm.h"
|
|
|
|
|
#include "util-spm-bm.h"
|
|
|
|
|
|
|
|
|
|
#include "stream-tcp-reassemble.h"
|
|
|
|
|
#include "stream-tcp.h"
|
|
|
|
|
|
|
|
|
|
#include "app-layer.h"
|
|
|
|
|
#include "app-layer-dcerpc.h"
|
|
|
|
|
#include "decode-tcp.h"
|
|
|
|
|
#include "flow-util.h"
|
|
|
|
|
#include "util-debug.h"
|
|
|
|
|
|
|
|
|
|
#include "util-unittest.h"
|
|
|
|
|
#include "util-unittest-helper.h"
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Run the dce stub match functions for the dce stub based keywords.
|
|
|
|
|
*
|
|
|
|
|
* The following keywords are inspected:
|
|
|
|
|
* - content
|
|
|
|
|
* - isdaatat
|
|
|
|
|
* - pcre
|
|
|
|
|
* - bytejump
|
|
|
|
|
* - bytetest
|
|
|
|
|
*
|
|
|
|
|
* All keywords are evaluated against the dce stub data.
|
|
|
|
|
*
|
|
|
|
|
* For accounting the last match in relative matching,
|
|
|
|
|
* det_ctx->payload_offset var is used.
|
|
|
|
|
*
|
|
|
|
|
* \param de_ctx Detection engine context.
|
|
|
|
|
* \param det_ctx Detection engine thread context.
|
|
|
|
|
* \param s Signature to inspect.
|
|
|
|
|
* \param sm SigMatch to inspect.
|
|
|
|
|
* \param f Flow
|
|
|
|
|
* \param payload Pointer to the dce stub to inspect.
|
|
|
|
|
* \param payload_len Length of the payload
|
|
|
|
|
*
|
|
|
|
|
* \retval 0 No match.
|
|
|
|
|
* \retval 1 Match.
|
|
|
|
|
*/
|
|
|
|
|
static int DoInspectDcePayload(DetectEngineCtx *de_ctx,
|
|
|
|
|
DetectEngineThreadCtx *det_ctx, Signature *s,
|
|
|
|
|
SigMatch *sm, Flow *f, uint8_t *stub,
|
|
|
|
|
uint32_t stub_len, DCERPCState *dcerpc_state)
|
|
|
|
|
{
|
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
|
|
det_ctx->inspection_recursion_counter++;
|
|
|
|
|
|
|
|
|
|
if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) {
|
|
|
|
|
det_ctx->discontinue_matching = 1;
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sm == NULL || stub_len == 0) {
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(sm->type) {
|
|
|
|
|
case DETECT_CONTENT:
|
|
|
|
|
{
|
|
|
|
|
DetectContentData *cd = NULL;
|
|
|
|
|
cd = (DetectContentData *)sm->ctx;
|
|
|
|
|
SCLogDebug("inspecting content %"PRIu32" stub_len %"PRIu32,
|
|
|
|
|
cd->id, stub_len);
|
|
|
|
|
|
|
|
|
|
/* rule parsers should take care of this */
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
BUG_ON(cd->depth != 0 && cd->depth <= cd->offset);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* search for our pattern, checking the matches recursively.
|
|
|
|
|
* if we match we look for the next SigMatch as well */
|
|
|
|
|
uint8_t *found = NULL;
|
|
|
|
|
uint32_t offset = 0;
|
|
|
|
|
uint32_t depth = stub_len;
|
|
|
|
|
uint32_t prev_offset = 0; /**< used in recursive searching */
|
|
|
|
|
uint32_t prev_payload_offset = det_ctx->payload_offset;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_DISTANCE ||
|
|
|
|
|
cd->flags & DETECT_CONTENT_WITHIN) {
|
|
|
|
|
SCLogDebug("prev_payload_offset %"PRIu32,
|
|
|
|
|
prev_payload_offset);
|
|
|
|
|
|
|
|
|
|
offset = prev_payload_offset;
|
|
|
|
|
depth = stub_len;
|
|
|
|
|
|
|
|
|
|
int distance = cd->distance;
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_DISTANCE) {
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_DISTANCE_BE) {
|
|
|
|
|
distance = det_ctx->bj_values[cd->distance];
|
|
|
|
|
}
|
|
|
|
|
if (distance < 0 && (uint32_t)(abs(distance)) > offset)
|
|
|
|
|
offset = 0;
|
|
|
|
|
else
|
|
|
|
|
offset += distance;
|
|
|
|
|
|
|
|
|
|
SCLogDebug("cd->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32,
|
|
|
|
|
cd->distance, offset, depth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_WITHIN) {
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_WITHIN_BE) {
|
|
|
|
|
if ((int32_t)depth > (int32_t)(prev_payload_offset + det_ctx->bj_values[cd->within] + distance)) {
|
|
|
|
|
depth = prev_payload_offset + det_ctx->bj_values[cd->within] + distance;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ((int32_t)depth > (int32_t)(prev_payload_offset + cd->within + distance)) {
|
|
|
|
|
depth = prev_payload_offset + cd->within + distance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("cd->within %"PRIi32", prev_payload_offset "
|
|
|
|
|
"%"PRIu32", depth %"PRIu32, cd->within,
|
|
|
|
|
prev_payload_offset, depth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_DEPTH_BE) {
|
|
|
|
|
if ((det_ctx->bj_values[cd->depth] + prev_payload_offset) < depth) {
|
|
|
|
|
depth = prev_payload_offset + det_ctx->bj_values[cd->depth];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (cd->depth != 0) {
|
|
|
|
|
if ((cd->depth + prev_payload_offset) < depth) {
|
|
|
|
|
depth = prev_payload_offset + cd->depth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("cd->depth %"PRIu32", depth %"PRIu32,
|
|
|
|
|
cd->depth, depth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_OFFSET_BE) {
|
|
|
|
|
if (det_ctx->bj_values[cd->offset] > offset)
|
|
|
|
|
offset = det_ctx->bj_values[cd->offset];
|
|
|
|
|
} else {
|
|
|
|
|
if (cd->offset > offset) {
|
|
|
|
|
offset = cd->offset;
|
|
|
|
|
SCLogDebug("setting offset %"PRIu32, offset);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* implied no relative matches */
|
|
|
|
|
} else {
|
|
|
|
|
/* set depth */
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_DEPTH_BE) {
|
|
|
|
|
depth = det_ctx->bj_values[cd->depth];
|
|
|
|
|
} else {
|
|
|
|
|
if (cd->depth != 0) {
|
|
|
|
|
depth = cd->depth;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set offset */
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_OFFSET_BE)
|
|
|
|
|
offset = det_ctx->bj_values[cd->offset];
|
|
|
|
|
else
|
|
|
|
|
offset = cd->offset;
|
|
|
|
|
prev_payload_offset = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* update offset with prev_offset if we're searching for
|
|
|
|
|
* matches after the first occurence. */
|
|
|
|
|
SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, offset,
|
|
|
|
|
prev_offset);
|
|
|
|
|
if (prev_offset != 0)
|
|
|
|
|
offset = prev_offset;
|
|
|
|
|
|
|
|
|
|
SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth);
|
|
|
|
|
|
|
|
|
|
if (depth > stub_len)
|
|
|
|
|
depth = stub_len;
|
|
|
|
|
|
|
|
|
|
/* if offset is bigger than depth we can never match on a
|
|
|
|
|
* pattern. We can however, "match" on a negated pattern. */
|
|
|
|
|
/* \todo why isn't it >= ?. Same question applies for
|
|
|
|
|
* detect-engine-dcepayload.c and detect-engine-uri.c */
|
|
|
|
|
if (offset > depth || depth == 0) {
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_NEGATED) {
|
|
|
|
|
goto match;
|
|
|
|
|
} else {
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t *sstub = stub + offset;
|
|
|
|
|
uint32_t sstub_len = depth - offset;
|
|
|
|
|
uint32_t match_offset = 0;
|
|
|
|
|
SCLogDebug("sstub_len %"PRIu32, sstub_len);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
BUG_ON(sstub_len > stub_len);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* do the actual search */
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
|
found = BoyerMooreNocase(cd->content, cd->content_len, sstub,
|
|
|
|
|
sstub_len, cd->bm_ctx->bmGs,
|
|
|
|
|
cd->bm_ctx->bmBc);
|
|
|
|
|
} else {
|
|
|
|
|
found = BoyerMoore(cd->content, cd->content_len, sstub,
|
|
|
|
|
sstub_len, cd->bm_ctx->bmGs,
|
|
|
|
|
cd->bm_ctx->bmBc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* next we evaluate the result in combination with the
|
|
|
|
|
* negation flag. */
|
|
|
|
|
SCLogDebug("found %p cd negated %s", found,
|
|
|
|
|
cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false");
|
|
|
|
|
|
|
|
|
|
if (found == NULL && !(cd->flags & DETECT_CONTENT_NEGATED)) {
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
} else if (found == NULL && cd->flags & DETECT_CONTENT_NEGATED) {
|
|
|
|
|
goto match;
|
|
|
|
|
} else if (found != NULL && cd->flags & DETECT_CONTENT_NEGATED) {
|
|
|
|
|
SCLogDebug("content %"PRIu32" matched at offset %"PRIu32", but "
|
|
|
|
|
"negated so no match", cd->id, match_offset);
|
|
|
|
|
det_ctx->discontinue_matching = 1;
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
} else {
|
|
|
|
|
match_offset = (uint32_t)((found - stub) + cd->content_len);
|
|
|
|
|
SCLogDebug("content %"PRIu32" matched at offset %"PRIu32"",
|
|
|
|
|
cd->id, match_offset);
|
|
|
|
|
det_ctx->payload_offset = match_offset;
|
|
|
|
|
|
|
|
|
|
if (!(cd->flags & DETECT_CONTENT_RELATIVE_NEXT)) {
|
|
|
|
|
SCLogDebug("no relative match coming up, so this is a match");
|
|
|
|
|
goto match;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* bail out if we have no next match. Technically this is an
|
|
|
|
|
* error, as the current cd has the DETECT_CONTENT_RELATIVE_NEXT
|
|
|
|
|
* flag set. */
|
|
|
|
|
if (sm->next == NULL) {
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("content %"PRIu32, cd->id);
|
|
|
|
|
|
|
|
|
|
/* see if the next payload keywords match. If not, we will
|
|
|
|
|
* search for another occurence of this content and see
|
|
|
|
|
* if the others match then until we run out of matches */
|
|
|
|
|
int r = DoInspectDcePayload(de_ctx, det_ctx, s, sm->next,
|
|
|
|
|
f, stub, stub_len, dcerpc_state);
|
|
|
|
|
if (r == 1) {
|
|
|
|
|
SCReturnInt(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (det_ctx->discontinue_matching)
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
|
|
|
|
|
/* set the previous match offset to the start of this match + 1 */
|
|
|
|
|
prev_offset = (match_offset - (cd->content_len - 1));
|
|
|
|
|
SCLogDebug("trying to see if there is another match after "
|
|
|
|
|
"prev_offset %"PRIu32, prev_offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case DETECT_ISDATAAT:
|
|
|
|
|
{
|
|
|
|
|
SCLogDebug("inspecting isdataat");
|
|
|
|
|
|
|
|
|
|
DetectIsdataatData *id = (DetectIsdataatData *)sm->ctx;
|
|
|
|
|
if (id->flags & ISDATAAT_RELATIVE) {
|
|
|
|
|
if (det_ctx->payload_offset + id->dataat > stub_len) {
|
|
|
|
|
SCLogDebug("det_ctx->payload_offset + id->dataat "
|
|
|
|
|
"%"PRIu32" > %"PRIu32,
|
|
|
|
|
det_ctx->payload_offset + id->dataat, stub_len);
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug("relative isdataat match");
|
|
|
|
|
goto match;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (id->dataat < stub_len) {
|
|
|
|
|
SCLogDebug("absolute isdataat match");
|
|
|
|
|
goto match;
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", "
|
|
|
|
|
"stub_len %"PRIu32"", id->dataat, stub_len);
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case DETECT_PCRE:
|
|
|
|
|
{
|
|
|
|
|
SCLogDebug("inspecting pcre");
|
|
|
|
|
DetectPcreData *pe = (DetectPcreData *)sm->ctx;
|
|
|
|
|
uint32_t prev_payload_offset = det_ctx->payload_offset;
|
|
|
|
|
uint32_t prev_offset = 0;
|
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
|
|
det_ctx->pcre_match_start_offset = 0;
|
|
|
|
|
do {
|
|
|
|
|
r = DetectPcrePayloadMatch(det_ctx, s, sm, NULL, f,
|
|
|
|
|
stub, stub_len);
|
|
|
|
|
if (r == 0) {
|
|
|
|
|
det_ctx->discontinue_matching = 1;
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(pe->flags & DETECT_PCRE_RELATIVE_NEXT)) {
|
|
|
|
|
SCLogDebug("no relative match coming up, so this is a match");
|
|
|
|
|
goto match;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* save it, in case we need to do a pcre match once again */
|
|
|
|
|
prev_offset = det_ctx->pcre_match_start_offset;
|
|
|
|
|
|
|
|
|
|
/* see if the next payload keywords match. If not, we will
|
|
|
|
|
* search for another occurence of this pcre and see
|
|
|
|
|
* if the others match, until we run out of matches */
|
|
|
|
|
r = DoInspectDcePayload(de_ctx, det_ctx, s, sm->next, f, stub,
|
|
|
|
|
stub_len, dcerpc_state);
|
|
|
|
|
if (r == 1) {
|
|
|
|
|
SCReturnInt(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (det_ctx->discontinue_matching)
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
|
|
|
|
|
det_ctx->payload_offset = prev_payload_offset;
|
|
|
|
|
det_ctx->pcre_match_start_offset = prev_offset;
|
|
|
|
|
} while (1);
|
|
|
|
|
}
|
|
|
|
|
case DETECT_BYTETEST:
|
|
|
|
|
{
|
|
|
|
|
DetectBytetestData *data = (DetectBytetestData *)sm->ctx;
|
|
|
|
|
uint8_t flags = data->flags;
|
|
|
|
|
int32_t offset = data->offset;;
|
|
|
|
|
uint64_t value = data->value;
|
|
|
|
|
if (flags & DETECT_BYTETEST_OFFSET_BE) {
|
|
|
|
|
offset = det_ctx->bj_values[offset];
|
|
|
|
|
}
|
|
|
|
|
if (flags & DETECT_BYTETEST_VALUE_BE) {
|
|
|
|
|
value = det_ctx->bj_values[value];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if we have dce enabled we will have to use the endianness
|
|
|
|
|
* specified by the dce header */
|
|
|
|
|
if (flags & DETECT_BYTETEST_DCE) {
|
|
|
|
|
/* enable the endianness flag temporarily. once we are done
|
|
|
|
|
* processing we reset the flags to the original value*/
|
|
|
|
|
flags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ?
|
|
|
|
|
DETECT_BYTETEST_LITTLE: 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DetectBytetestDoMatch(det_ctx, s, sm, stub, stub_len, flags, offset, value) != 1) {
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto match;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case DETECT_BYTEJUMP:
|
|
|
|
|
{
|
|
|
|
|
DetectBytejumpData *data = (DetectBytejumpData *)sm->ctx;
|
|
|
|
|
uint8_t flags = data->flags;
|
|
|
|
|
int32_t offset = data->offset;;
|
|
|
|
|
if (flags & DETECT_BYTEJUMP_OFFSET_BE) {
|
|
|
|
|
offset = det_ctx->bj_values[offset];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if we have dce enabled we will have to use the endianness
|
|
|
|
|
* specified by the dce header */
|
|
|
|
|
if (flags & DETECT_BYTEJUMP_DCE) {
|
|
|
|
|
/* enable the endianness flag temporarily. once we are done
|
|
|
|
|
* processing we reset the flags to the original value*/
|
|
|
|
|
flags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ?
|
|
|
|
|
DETECT_BYTEJUMP_LITTLE : 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DetectBytejumpDoMatch(det_ctx, s, sm, stub, stub_len, flags, offset) != 1) {
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto match;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case DETECT_BYTE_EXTRACT:
|
|
|
|
|
{
|
|
|
|
|
DetectByteExtractData *bed = (DetectByteExtractData *)sm->ctx;
|
|
|
|
|
uint8_t endian = bed->endian;
|
|
|
|
|
|
|
|
|
|
/* if we have dce enabled we will have to use the endianness
|
|
|
|
|
* specified by the dce header */
|
|
|
|
|
if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN &&
|
|
|
|
|
endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) {
|
|
|
|
|
|
|
|
|
|
/* enable the endianness flag temporarily. once we are done
|
|
|
|
|
* processing we reset the flags to the original value*/
|
|
|
|
|
endian |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] == 0x10) ?
|
|
|
|
|
DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG);
|
|
|
|
|
}
|
|
|
|
|
if (DetectByteExtractDoMatch(det_ctx, sm, s, stub, stub_len,
|
|
|
|
|
&det_ctx->bj_values[bed->local_id], endian) != 1) {
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto match;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we should never get here, but bail out just in case */
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
SCLogDebug("sm->type %u", sm->type);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
BUG_ON(1);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
|
|
|
|
|
match:
|
|
|
|
|
/* this sigmatch matched, inspect the next one. If it was the last,
|
|
|
|
|
* the payload portion of the signature matched. */
|
|
|
|
|
if (sm->next != NULL) {
|
|
|
|
|
int r = DoInspectDcePayload(de_ctx, det_ctx, s, sm->next, f, stub,
|
|
|
|
|
stub_len, dcerpc_state);
|
|
|
|
|
SCReturnInt(r);
|
|
|
|
|
} else {
|
|
|
|
|
SCReturnInt(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Do the content inspection & validation for a signature against dce stub.
|
|
|
|
|
*
|
|
|
|
|
|