70 #define IS_REX_PREFIX(b) ((ND_PREFIX_REX_MIN <= (b)) && ((b) <= ND_PREFIX_REX_MAX)) 78 if (0x90 == *Buffer || 0xcc == *Buffer)
83 else if (BufSize >= 2 &&
84 (0x84 == Buffer[0] || 0x85 == Buffer[0]) &&
90 else if (BufSize >= 2 &&
96 else if (0xc3 == *Buffer || 0xcb == *Buffer)
101 else if (BufSize >= 5 &&
107 else if (BufSize >= 6 &&
108 0xff == Buffer[0] && 0x15 == Buffer[1])
113 else if (BufSize >= 5 &&
119 else if (BufSize >= 2 &&
125 else if (BufSize >= 2 &&
126 (0x70 <= *Buffer && *Buffer <= 0x7f))
131 else if (BufSize >= 3 &&
132 (0xc2 == *Buffer || 0xca == *Buffer))
137 else if (0xaa <= *Buffer && *Buffer <= 0xad)
142 else if (0x9c == *Buffer || 0x9d == *Buffer)
150 else if (0x91 <= *Buffer && *Buffer <= 0x97)
155 else if (BufSize >= 2 &&
156 (0xb0 <= *Buffer && *Buffer <= 0xb7))
165 else if (BufSize >= 5 &&
166 (0xb8 <= *Buffer && *Buffer <= 0xbf))
175 else if (0x50 <= *Buffer && *Buffer <= 0x5f)
180 else if (BufSize >= 2 &&
186 else if (BufSize >= 3 &&
188 (0xc0 <= Buffer[1] && Buffer[1] <= 0xcf))
193 else if (0x98 == *Buffer || 0x99 == *Buffer)
198 else if (BufSize >= 5 &&
204 else if (BufSize >= 2 &&
205 0x00 == Buffer[0] && 0x00 == Buffer[1])
210 else if (BufSize >= 3 &&
211 (0x83 == Buffer[0] && (0xe0 <= Buffer[1] && Buffer[1] <= 0xe3)))
216 else if (BufSize >= 2 &&
223 else if (BufSize >= 4 &&
224 0x89 == Buffer[0] && 0x24 == Buffer[2] &&
225 (0x4c == Buffer[1] ||
243 else if (BufSize >= 7 &&
244 0x89 == Buffer[0] && 0x24 == Buffer[2] &&
245 (0x8c == Buffer[1] ||
263 else if (BufSize >= 6 &&
264 0x81 == Buffer[0] && 0xc4 == Buffer[1])
269 else if (BufSize >= 3 &&
270 0x83 == Buffer[0] && 0xc4 == Buffer[1])
275 else if (BufSize >= 6 &&
276 0x81 == Buffer[0] && 0xec == Buffer[1])
281 else if (BufSize >= 3 &&
282 0x83 == Buffer[0] && 0xec == Buffer[1])
287 else if (BufSize >= 2 &&
288 (0x8b == Buffer[0] || 0x89 == Buffer[0]) &&
299 else if (BufSize >= 6 &&
301 (0x80 <= Buffer[1] && Buffer[1] <= 0x8f))
306 else if (BufSize >= 2 &&
308 (0xc0 <= Buffer[1] && Buffer[1] <= 0xcf))
313 else if (BufSize >= 2 &&
323 if (0x40 <= *Buffer && *Buffer <= 0x4f)
332 0x48 == Buffer[0] && 0x83 == Buffer[1] && 0xc4 == Buffer[2])
337 else if (BufSize >= 7 &&
338 0x48 == Buffer[0] && 0x81 == Buffer[1] && 0xec == Buffer[2])
343 else if (BufSize >= 5 &&
344 (0x48 == Buffer[0] || 0x4c == Buffer[0]) &&
345 (0x89 == Buffer[1] || 0x8b == Buffer[1]) &&
347 (0x4c == Buffer[2] ||
365 else if (BufSize >= 8 &&
366 (0x48 == Buffer[0] || 0x4c == Buffer[0]) &&
367 (0x89 == Buffer[1] || 0x8b == Buffer[1]) &&
369 (0x8c == Buffer[2] ||
387 else if (BufSize >= 4
388 && 0x48 == Buffer[0] && 0x83 == Buffer[1] && 0xec == Buffer[2])
402 else if (BufSize >= 3 &&
409 else if (BufSize >= 3 &&
411 (0xc0 <= Buffer[2] && Buffer[2] <= 0xcf))
416 else if (BufSize >= 6 &&
417 0 == (*Buffer &
BIT(3)) &&
418 (0xb8 <= Buffer[1] && Buffer[1] <= 0xbf))
427 else if (BufSize >= 10 &&
428 0 != (*Buffer &
BIT(3)) &&
429 (0xb8 <= Buffer[1] && Buffer[1] <= 0xbf))
438 else if (BufSize >= 4 &&
440 (0x45 == Buffer[2] ||
446 else if (BufSize >= 5 &&
449 (0x44 == Buffer[2] ||
457 else if (BufSize >= 3 &&
458 (0x8b == Buffer[1] || 0x89 == Buffer[1]) &&
469 else if (BufSize >= 3 &&
470 ((0x84 == Buffer[1] || 0x85 == Buffer[1]) &&
471 (0xc0 <= Buffer[2])))
476 else if (BufSize >= 6 &&
482 else if (BufSize >= 2 &&
483 (0x98 == Buffer[1] || 0x99 == Buffer[1]))
488 else if (BufSize >= 2 &&
489 (0x50 <= Buffer[1] && Buffer[1] <= 0x5f))
545 if (0 == PatternSize)
555 if (NULL == TotalExtracted)
560 if (NULL == TotalParsed)
565 if (MaxBufferSize <= ND_MAX_INSTRUCTION_LENGTH)
570 end = Buffer + MaxBufferSize;
576 WARNING(
"[WARNING] Extracting codeblocks for 16 bit!\n");
579 while ((Buffer < end) && (i < PatternSize))
582 DWORD pattern, skipSize;
590 Pattern[i++] = (
BYTE)pattern;
594 *TotalParsed += skipSize;
604 if (
__unlikely(ndstatus == ND_STATUS_BUFFER_TOO_SMALL))
616 if (Buffer + instrux.Length >= end)
623 if (instrux.Instruction == ND_INS_Jcc)
629 else if (instrux.Instruction == ND_INS_JMPE ||
630 instrux.Instruction == ND_INS_JMPFD ||
631 instrux.Instruction == ND_INS_JMPFI ||
632 instrux.Instruction == ND_INS_JMPNI ||
633 instrux.Instruction == ND_INS_JMPNR)
637 else if (instrux.Instruction == ND_INS_CALLFD ||
638 instrux.Instruction == ND_INS_CALLFI ||
639 instrux.Instruction == ND_INS_CALLNI ||
640 instrux.Instruction == ND_INS_CALLNR)
644 else if (instrux.Instruction == ND_INS_RETF ||
645 instrux.Instruction == ND_INS_RETN)
649 else if (instrux.Instruction == ND_INS_STOS ||
650 instrux.Instruction == ND_INS_LODS)
654 else if (instrux.Instruction == ND_INS_XCHG ||
655 instrux.Instruction == ND_INS_CMPXCHG)
659 else if (instrux.Instruction == ND_INS_BT ||
660 instrux.Instruction == ND_INS_BTC ||
661 instrux.Instruction == ND_INS_BTR ||
662 instrux.Instruction == ND_INS_BTS)
670 goto _next_instruction;
673 if (instrux.Instruction == ND_INS_MOV)
675 if (instrux.Operands[0].Type == ND_OP_REG &&
676 instrux.Operands[1].Type == ND_OP_REG)
680 else if (instrux.Operands[0].Type == ND_OP_MEM ||
681 instrux.Operands[1].Type == ND_OP_MEM)
685 else if (instrux.HasImm1)
689 else if (instrux.Seg == ND_PREFIX_G2_SEG_FS ||
690 instrux.Seg == ND_PREFIX_G2_SEG_GS)
695 else if (instrux.Instruction == ND_INS_PUSHF ||
696 instrux.Instruction == ND_INS_POPF)
704 goto _next_instruction;
708 if (skipSize && ((
DWORD)oldPattern != pattern))
710 ERROR(
"[ERROR] [CRITICAL] Pattern was %02d but we returned %02d.." 711 "The MALWARE / ROOTKIT below is most probably a FP!\n",
720 Pattern[i++] = oldPattern;
725 Buffer += instrux.Length;
726 *TotalParsed += instrux.Length;
733 *TotalParsed = MaxBufferSize;
775 DWORD i, j, totalParsed, currentHash, sizeToParse;
784 if (MaxBufferSize <= ND_MAX_INSTRUCTION_LENGTH)
789 if (NULL == HashesCount || 0 == *HashesCount)
801 sizeToParse = MaxBufferSize - ND_MAX_INSTRUCTION_LENGTH;
808 while (totalParsed < sizeToParse && currentHash < *HashesCount)
810 DWORD patternSize = 0;
813 sizeToParse - totalParsed,
824 WARNING(
"[WARNNING] Buffer too small to extract codeblocks (size %d): 0x%08x\n",
825 sizeToParse - totalParsed,
832 ERROR(
"[ERROR] IntFragExtractCodePattern: 0x%08x\n", status);
838 for (i = 0; i < patternSize; i++)
867 chunks[j] = pattern[i + j];
884 if (++currentHash == *HashesCount)
899 *HashesCount = currentHash;
940 if (0 == CodeBlocksCount)
945 if (NULL == ExceptionSignature)
951 for (i = 0; i < ExceptionSignature->ListsCount; i++)
954 DWORD j, remaining, currentCb;
956 remaining = ExceptionSignature->Score;
959 for (j = 0; j < pSigHash->
Count; j++)
961 for (; currentCb < CodeBlocksCount; currentCb++)
963 if (pSigHash->
Hashes[j] < Hashes[currentCb])
967 else if (pSigHash->
Hashes[j] == Hashes[currentCb])
975 if ((
int)remaining <= 0)
1025 DWORD i, currentOffset;
1033 if (NULL == TotalExtracted)
1038 if (NULL == Pattern)
1043 if (MaxBufferSize <= ND_MAX_INSTRUCTION_LENGTH)
1048 end = Buffer + MaxBufferSize - ND_MAX_INSTRUCTION_LENGTH;
1050 currentOffset = StartOffset;
1055 WARNING(
"[WARNING] Extracting codeblocks for 16 bit!\n");
1058 *TotalExtracted = 0;
1060 while ((Buffer < end) && (i < PatternSize))
1065 if (!ND_SUCCESS(ndstatus))
1072 if (Buffer + instrux.Length >= end)
1077 if (instrux.Instruction == ND_INS_Jcc)
1080 Pattern[i++].Offset = currentOffset;
1082 else if (instrux.Instruction == ND_INS_JMPE ||
1083 instrux.Instruction == ND_INS_JMPFD ||
1084 instrux.Instruction == ND_INS_JMPFI ||
1085 instrux.Instruction == ND_INS_JMPNI ||
1086 instrux.Instruction == ND_INS_JMPNR)
1089 Pattern[i++].Offset = currentOffset;
1091 else if (instrux.Instruction == ND_INS_CALLFD ||
1092 instrux.Instruction == ND_INS_CALLFI ||
1093 instrux.Instruction == ND_INS_CALLNI ||
1094 instrux.Instruction == ND_INS_CALLNR)
1097 Pattern[i++].Offset = currentOffset;
1099 else if (instrux.Instruction == ND_INS_RETF ||
1100 instrux.Instruction == ND_INS_RETN)
1103 Pattern[i++].Offset = currentOffset;
1105 else if (instrux.Instruction == ND_INS_STOS ||
1106 instrux.Instruction == ND_INS_LODS)
1109 Pattern[i++].Offset = currentOffset;
1111 else if (instrux.Instruction == ND_INS_XCHG ||
1112 instrux.Instruction == ND_INS_CMPXCHG)
1115 Pattern[i++].Offset = currentOffset;
1117 else if (instrux.Instruction == ND_INS_BT ||
1118 instrux.Instruction == ND_INS_BTC ||
1119 instrux.Instruction == ND_INS_BTR ||
1120 instrux.Instruction == ND_INS_BTS)
1123 Pattern[i++].Offset = currentOffset;
1129 goto _next_instruction;
1132 if (instrux.Instruction == ND_INS_MOV)
1134 if (instrux.Operands[0].Type == ND_OP_REG &&
1135 instrux.Operands[1].Type == ND_OP_REG)
1138 Pattern[i++].Offset = currentOffset;
1140 else if (instrux.Operands[0].Type == ND_OP_MEM ||
1141 instrux.Operands[1].Type == ND_OP_MEM)
1144 Pattern[i++].Offset = currentOffset;
1146 else if (instrux.HasImm1)
1149 Pattern[i++].Offset = currentOffset;
1151 else if (instrux.Seg == ND_PREFIX_G2_SEG_FS ||
1152 instrux.Seg == ND_PREFIX_G2_SEG_GS)
1155 Pattern[i++].Offset = currentOffset;
1158 else if (instrux.Instruction == ND_INS_PUSHF ||
1159 instrux.Instruction == ND_INS_POPF)
1162 Pattern[i++].Offset = currentOffset;
1168 goto _next_instruction;
1172 Buffer += instrux.Length;
1173 currentOffset += instrux.Length;
1176 *TotalExtracted = i;
1202 DWORD previousOffset;
1204 int maxLength =
sizeof(
gCbLog);
1205 CHAR *pCbLine = NULL;
1216 previousOffset = CodeBlock[0].OffsetStart;
1217 for (
DWORD i = 0; i < Count; i++)
1219 if (i % ElemLine == 0)
1225 *(pCbLine - 2) =
' ';
1231 maxLength =
sizeof(
gCbLog);
1233 ret = snprintf(pCbLine, maxLength,
"[CODEBLOCKS] ");
1234 if (ret < 0 || ret >= maxLength)
1236 ERROR(
"[ERROR] snprintf error: %d, size %d\n", ret, maxLength);
1248 if (!loggedRip && ((previousOffset <= RipOffset && RipOffset <= CodeBlock[i].OffsetStart) ||
1249 (i == 0 && CodeBlock[i].OffsetStart >= RipOffset) ||
1253 ret = snprintf(pCbLine, maxLength,
"(%7s->0x%016llx), ", ReturnRip ?
"Ret RIP" :
"RIP", Rip);
1254 if (ret < 0 || ret >= maxLength)
1256 ERROR(
"[ERROR] snprintf error: %d, size %d\n", ret, maxLength);
1268 ret = snprintf(pCbLine, maxLength,
"0x%08x (0x%03x, %9s), ", CodeBlock[i].Hash, CodeBlock[i].OffsetStart,
1269 (CodeBlock[i].PivotInstruction ==
codeInsCall) ?
"CALL" :
1270 (CodeBlock[i].PivotInstruction ==
codeInsJmp) ?
"JMP" :
1271 (CodeBlock[i].PivotInstruction ==
codeInsMovMem) ?
"MOV MEM" :
1272 (CodeBlock[i].PivotInstruction ==
codeInsMovFsGs) ?
"MOV FS/GS" :
"INVALID");
1273 if (ret < 0 || ret >= maxLength)
1275 ERROR(
"[ERROR] snprintf error: %d, size %d\n", ret, maxLength);
1284 previousOffset = CodeBlock[i].OffsetStart;
1287 *(pCbLine - 2) =
' ';
1321 DWORD i, j, patternSize, currentCb, previousOffset;
1322 DWORD cbCount, ripOffset;
1330 if (0 == MaxBufferSize)
1337 patternSize = currentCb = previousOffset = 0;
1348 if (NULL == pattern)
1356 StartAddress & PAGE_OFFSET,
1367 WARNING(
"[WARNNING] Buffer too small to extract codeblocks (size %d): 0x%08x\n", MaxBufferSize, status);
1371 ERROR(
"[ERROR] IntFragExtractCodePattern: 0x%08x\n", status);
1379 WARNING(
"[WARNING] Could not extract enough code-blocks: %d\n", patternSize);
1408 pCdBlk[currentCb].
Chunks[j] = pattern[i + j].
Value;
1409 pCdBlk[currentCb].
Size++;
1413 if (++currentCb >= cbCount)
INTSTATUS IntFragExtractCodePattern(PBYTE Buffer, DWORD StartOffset, DWORD MaxBufferSize, IG_CS_TYPE CsType, CB_EXTRACT_LEVEL ExtractLevel, DWORD PatternSize, CODE_BLOCK_PATTERN *Pattern, DWORD *TotalExtracted)
Extract a pattern of code-blocks from the given code buffer.
DWORD IntFragHandleCommon(const BYTE *Buffer, size_t BufSize, IG_CS_TYPE CsType, CB_EXTRACT_LEVEL ExtractLevel, DWORD *Pattern)
Extract a pattern of instructions without using the disassembler.
A mov using a segment:offset.
DWORD Crc32Compute(const void *Buffer, size_t Size, DWORD InitialCrc)
Computes the CRC for a byte array.
INTSTATUS IntFragExtractPattern(BYTE *Buffer, DWORD MaxBufferSize, IG_CS_TYPE CsType, CB_EXTRACT_LEVEL ExtractLevel, DWORD PatternSize, BYTE *Pattern, DWORD *TotalExtracted, DWORD *TotalParsed)
Extract a pattern of code-blocks from the given code buffer.
#define INT_STATUS_SUCCESS
Non-conditional jump, of any kind.
DWORD OffsetStart
The start of the extracted codeblock (not actually relevant)
#define INT_SUCCESS(Status)
WORD Size
Code block size, in patterns.
#define INT_STATUS_SIGNATURE_MATCHED
DWORD Offset
The offset of the instruction in the page.
#define CODE_BLOCK_CHUNKS_COUNT
Number of chunks (CODE_INS) per codeblock.
A mov using immediate value.
#define HpAllocWithTag(Len, Tag)
int INTSTATUS
The status data type.
#define INT_STATUS_NOT_FOUND
#define _Out_writes_(expr)
Exchange instruction, including xchg, xadd, cmpxchg, cmpxchg8b/16b.
Bit manipulation instruction - bt, bts, btr, btc.
BYTE Chunks[CODE_BLOCK_CHUNKS_COUNT]
The actual CODE_INS values representing the instruction pattern.
IG_CS_TYPE
The type of the code segment.
static CHAR gCbLog[512]
Used to format log lines containing code-blocks.
INTSTATUS IntFragDumpBlocks(PBYTE Buffer, QWORD StartAddress, DWORD MaxBufferSize, IG_CS_TYPE CsType, CB_EXTRACT_LEVEL ExtractLevel, QWORD Rip, BOOLEAN ReturnRip)
Dumps code-blocks that can then be used to generate an exception signature.
TIMER_FRIENDLY void IntDumpInstruction(INSTRUX *Instruction, QWORD Rip)
This function dumps a given instruction (textual disassembly).
#define INITIAL_CRC_VALUE
Conditional jump, of any kind, including loop.
INTSTATUS IntFragExtractCodeBlocks(BYTE *Buffer, DWORD MaxBufferSize, IG_CS_TYPE CsType, CB_EXTRACT_LEVEL ExtractLevel, DWORD *HashesCount, DWORD *Hashes)
Extract a block of code-block hashes from the given code buffer.
INTSTATUS IntDecDecodeInstructionFromBuffer(PBYTE Buffer, size_t BufferSize, IG_CS_TYPE CsType, void *Instrux)
Decode an instruction from the provided buffer.
#define HpFreeAndNullWithTag(Add, Tag)
This includes instructions until codeInsBt.
Not really used, only to signal an error.
#define INT_STATUS_INVALID_PARAMETER_5
BYTE Value
The CODE_INS value describing the instruction type.
static void IntFragLogCodeBlocks(CODE_BLOCK *CodeBlock, DWORD Count, QWORD Rip, DWORD RipOffset, BOOLEAN ReturnRip, DWORD ElemLine)
Log a block of code-blocks.
This includes instructions until codeInsFlags.
#define INT_STATUS_DATA_BUFFER_TOO_SMALL
DWORD Hashes[]
The list of hashes.
#define INT_STATUS_INVALID_PARAMETER_6
Some sort of string instruction - lods, stos, scas, movs.
BYTE Count
The number of hashes from the list.
__pure INTSTATUS IntFragMatchSignature(const DWORD *Hashes, DWORD CodeBlocksCount, const SIG_CODEBLOCKS *ExceptionSignature)
Match a block of code-block hashes against a list of code-block exception signatures.
struct _CODE_BLOCK CODE_BLOCK
#define INT_STATUS_INVALID_PARAMETER_8
#define INT_STATUS_INVALID_PARAMETER_1
A mov involving only registers.
#define _Out_writes_to_(expr, expr2)
A mov involving memory (either as the destination or as the source).
Describes a codeblocks signature.
#define INT_STATUS_INVALID_PARAMETER_2
Describe a codeblocks signature hash.
void UtilQuickSort(void *Array, const DWORD NumberOfElements, const BYTE ElementSize)
#define INT_STATUS_SIGNATURE_NOT_FOUND
#define INT_STATUS_INVALID_PARAMETER_7
#define INT_STATUS_INSUFFICIENT_RESOURCES
#define INT_STATUS_INVALID_PARAMETER_3