From f8a3011a4961cd68eaf0e766942476a512590dd7 Mon Sep 17 00:00:00 2001 From: Andrei Vlad LUTAS Date: Fri, 4 Dec 2020 10:52:56 +0200 Subject: [PATCH] Added support for AESDEC, AESDECLAST and AESIMC emulation, using compiler intrinsics - they will be used only if the SHEMU_OPT_SUPPORT_AES is set (so the integrator can properly check for AES-NI support in hardware). Fixed shemu option on Linux - make sure proper RIP is provided. --- CMakeLists.txt | 2 +- bdshemu/bdshemu.c | 59 +++++++++++++++++++++++++++++------ bdshemu/bdshemu.vcxproj | 26 +++++++++++---- disasmtool/disasmtool.c | 11 +++++++ disasmtool_lix/disasmtool.cpp | 14 ++++++++- inc/bdshemu.h | 3 ++ inc/version.h | 2 +- pybddisasm/setup.py | 2 +- 8 files changed, 100 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bb3c14..45ccf5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,7 @@ set(BDDISASM_COMPILE_OPTIONS -g3 -gdwarf-4 -grecord-gcc-switches - -march=nehalem + -march=westmere ) target_compile_options(bddisasm PRIVATE ${BDDISASM_COMPILE_OPTIONS}) diff --git a/bdshemu/bdshemu.c b/bdshemu/bdshemu.c index 3317cea..0504c90 100644 --- a/bdshemu/bdshemu.c +++ b/bdshemu/bdshemu.c @@ -10,7 +10,7 @@ #include "nd_crt.h" #include "bddisasm.h" #include "bdshemu.h" - +#include // // A generic emulator value. @@ -357,7 +357,7 @@ ShemuSetFlags( else if (FM_SHL == FlagsMode) { // CF is the last bit shifted out of the destination. - if (ND_GET_BIT(Src1, (Size * 8) - Src2)) + if (ND_GET_BIT(Src1, (Size * 8ULL) - Src2)) { Context->Registers.RegFlags |= NDR_RFLAG_CF; } @@ -368,7 +368,7 @@ ShemuSetFlags( if (Src2 == 1) { - if (ND_GET_BIT(Size * 8 - 1, Dst) ^ ND_GET_BIT(Src1, (Size * 8) - Src2)) + if (ND_GET_BIT(Size * 8ULL - 1, Dst) ^ ND_GET_BIT(Src1, (Size * 8ULL) - Src2)) { Context->Registers.RegFlags |= NDR_RFLAG_OF; } @@ -1351,6 +1351,7 @@ ShemuSetOperandValue( if (ShemuIsStackPtr(Context, gla, MAX(op->Size, Context->Instruction.WordLength))) { uint8_t stckstrlen = 0; + uint32_t i; // Note: only Context->Instruction.WordLength bits are flagged as RIP, as that is the RIP size. if (Context->Instruction.Instruction == ND_INS_CALLNR || @@ -1384,7 +1385,7 @@ ShemuSetOperandValue( // Note that we will ignore registers which have not been modified during emulation; those are considered // input values for the emulated code, and may be pointers or other data. We are interested only in // stack values built within the emulate code. - for (uint32_t i = 0; i < Value->Size; i++) + for (i = 0; i < Value->Size; i++) { unsigned char c = Value->Value.Bytes[i]; @@ -1402,7 +1403,7 @@ ShemuSetOperandValue( if (stckstrlen == Value->Size) { // Make sure the value is not present inside a non-dirty GPR. - for (uint32_t i = 0; i < 16; i++) + for (i = 0; i < 16; i++) { if (ShemuCmpGprValue(Context, i, Value->Size, Value->Value.Qwords[0], false) && (0 == (Context->DirtyGprBitmap & (1 << i)))) @@ -1696,6 +1697,7 @@ ShemuEmulate( { NDSTATUS ndstatus; uint64_t rip; + uint32_t i; // The stop flag has been set, this means we've reached a valid instruction, but that instruction cannot be // emulated (for example, SYSCALL, INT, system instructions, etc). @@ -2182,7 +2184,7 @@ ShemuEmulate( GET_OP(Context, 0, &dst); GET_OP(Context, 1, &src); - src.Value.Qwords[0] %= dst.Size * 8; + src.Value.Qwords[0] %= dst.Size * 8ULL; // Store the bit inside CF. SET_FLAG(Context, NDR_RFLAG_CF, (dst.Value.Qwords[0] >> src.Value.Qwords[0]) & 1); @@ -2811,7 +2813,7 @@ ShemuEmulate( case ND_INS_PXOR: GET_OP(Context, 0, &dst); GET_OP(Context, 1, &src); - for (uint32_t i = 0; i < dst.Size; i++) + for (i = 0; i < dst.Size; i++) { dst.Value.Bytes[i] ^= src.Value.Bytes[i]; } @@ -2839,7 +2841,7 @@ ShemuEmulate( case ND_INS_VPBROADCASTQ: GET_OP(Context, 1, &src); dst.Size = Context->Instruction.Operands[0].Size; - for (uint32_t i = 0; i < dst.Size / src.Size; i++) + for (i = 0; i < dst.Size / src.Size; i++) { switch (src.Size) { @@ -2863,7 +2865,7 @@ ShemuEmulate( case ND_INS_VPXOR: GET_OP(Context, 1, &dst); GET_OP(Context, 2, &src); - for (uint32_t i = 0; i < dst.Size; i++) + for (i = 0; i < dst.Size; i++) { dst.Value.Bytes[i] ^= src.Value.Bytes[i]; } @@ -2928,6 +2930,45 @@ ShemuEmulate( stop = true; break; + case ND_INS_AESIMC: + case ND_INS_AESDEC: + case ND_INS_AESDECLAST: + { + __m128i val, key; + + // Make sure AES support is present, and we can emulate AES decryption using AES instructions. + if (0 == (Context->Options & SHEMU_OPT_SUPPORT_AES)) + { + stop = true; + break; + } + + GET_OP(Context, 0, &dst); + GET_OP(Context, 1, &src); + + shemu_memcpy(&val, &dst, 16); + shemu_memcpy(&key, &src, 16); + + if (Context->Instruction.Instruction == ND_INS_AESDEC) + { + val = _mm_aesdec_si128(val, key); + } + else if (Context->Instruction.Instruction == ND_INS_AESDECLAST) + { + val = _mm_aesdeclast_si128(val, key); + } + else if (Context->Instruction.Instruction == ND_INS_AESIMC) + { + val = _mm_aesimc_si128(key); + } + + shemu_memcpy(&dst, &val, 16); + + SET_OP(Context, 0, &dst); + break; + } + + default: return SHEMU_ABORT_UNSUPPORTED_INSTRUX; } diff --git a/bdshemu/bdshemu.vcxproj b/bdshemu/bdshemu.vcxproj index d2b40e0..9fd7f31 100644 --- a/bdshemu/bdshemu.vcxproj +++ b/bdshemu/bdshemu.vcxproj @@ -50,8 +50,11 @@ StaticLibrary true - v142 + WindowsKernelModeDriver10.0 Unicode + Windows7 + Desktop + false StaticLibrary @@ -63,9 +66,12 @@ StaticLibrary false - v142 + WindowsKernelModeDriver10.0 true Unicode + Windows7 + Desktop + false StaticLibrary @@ -76,8 +82,11 @@ StaticLibrary true - v142 + WindowsKernelModeDriver10.0 Unicode + Windows7 + Desktop + false StaticLibrary @@ -89,9 +98,12 @@ StaticLibrary false - v142 + WindowsKernelModeDriver10.0 false Unicode + Windows7 + Desktop + false @@ -201,6 +213,7 @@ ..\inc;..\bddisasm\include;%(AdditionalIncludeDirectories) true $(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName).pdb + /kernel /d1import_no_registry /d2AllowCompatibleILVersions /d2Zi+ %(AdditionalOptions) Console @@ -259,7 +272,7 @@ Default false ProgramDatabase - /D "AMD64" %(AdditionalOptions) + /kernel /D "AMD64" %(AdditionalOptions) Console @@ -315,6 +328,7 @@ ..\inc;..\bddisasm\include;%(AdditionalIncludeDirectories) true $(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName).pdb + /kernel /d1nodatetime %(AdditionalOptions) Console @@ -386,7 +400,7 @@ $(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName).pdb Sync true - /D "AMD64" %(AdditionalOptions) + /kernel /D "AMD64" %(AdditionalOptions) Console diff --git a/disasmtool/disasmtool.c b/disasmtool/disasmtool.c index e15abcf..3708786 100644 --- a/disasmtool/disasmtool.c +++ b/disasmtool/disasmtool.c @@ -1520,6 +1520,17 @@ handle_shemu( ctx.StrThreshold = SHEMU_DEFAULT_STR_THRESHOLD; ctx.MemThreshold = SHEMU_DEFAULT_MEM_THRESHOLD; + // Check for AES support. + int regs[4] = { 0 }; + + __cpuid(regs, 1); + + // CPUID leaf function 1, register ECX, bit 25 indicates AES-NI support. + if (!!(regs[2] & (1UL << 25))) + { + ctx.Options |= SHEMU_OPT_SUPPORT_AES; + } + if (Options->UseShemuRegs) { // Copy the new GPRs diff --git a/disasmtool_lix/disasmtool.cpp b/disasmtool_lix/disasmtool.cpp index 627dee1..21e76bb 100644 --- a/disasmtool_lix/disasmtool.cpp +++ b/disasmtool_lix/disasmtool.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "external/argparse.h" @@ -526,7 +527,7 @@ void shemu(options &opts) ctx.IntbufSize = opts.actual_size + STACK_SIZE; ctx.Registers.RegFlags = NDR_RFLAG_IF | 2; - ctx.Registers.RegRip = opts.rip; + ctx.Registers.RegRip = opts.rip ? opts.rip : 0x200000; ctx.Segments.Cs.Selector = 0x10; ctx.Segments.Ds.Selector = 0x28; ctx.Segments.Es.Selector = 0x28; @@ -547,6 +548,17 @@ void shemu(options &opts) ctx.Options = SHEMU_OPT_TRACE_EMULATION; ctx.Log = shemu_log; ctx.AccessMemory = shemu_access_mem; + + uint32_t eax, ebx, ecx, edx; + + eax = ebx = ecx = edx = 0; + + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + + if (!!(ecx & (1UL << 25))) + { + ctx.Options |= SHEMU_OPT_SUPPORT_AES; + } // Configurable thresholds. ctx.NopThreshold = SHEMU_DEFAULT_NOP_THRESHOLD; diff --git a/inc/bdshemu.h b/inc/bdshemu.h index 31080af..1453e9c 100644 --- a/inc/bdshemu.h +++ b/inc/bdshemu.h @@ -263,6 +263,9 @@ typedef unsigned int SHEMU_STATUS; // #define SHEMU_OPT_TRACE_EMULATION 0x00000001 // Trace each emulated instruction. #define SHEMU_OPT_STOP_ON_EXPLOIT 0x00000002 // When shellcode indications are confirmed, stop emulation. +#define SHEMU_OPT_SUPPORT_AES 0x00010000 // Indicates that AES instructions are supported, and + // therefore, the AES intrinsics can be used to emulate + // AES decryption. // diff --git a/inc/version.h b/inc/version.h index 2be1746..65d24ee 100644 --- a/inc/version.h +++ b/inc/version.h @@ -7,6 +7,6 @@ #define DISASM_VERSION_MAJOR 1 #define DISASM_VERSION_MINOR 31 -#define DISASM_VERSION_REVISION 4 +#define DISASM_VERSION_REVISION 5 #endif // DISASM_VER_H diff --git a/pybddisasm/setup.py b/pybddisasm/setup.py index 7f32fbd..2c892a3 100644 --- a/pybddisasm/setup.py +++ b/pybddisasm/setup.py @@ -12,7 +12,7 @@ from setuptools import find_packages, setup, Command, Extension, Distribution from codecs import open VERSION = (0, 1, 3) -LIBRARY_VERSION = (1, 31, 4) +LIBRARY_VERSION = (1, 31, 5) LIBRARY_INSTRUX_SIZE = 864 packages = ['pybddisasm']