diff --git a/bdshemu/bdshemu.c b/bdshemu/bdshemu.c index d2926ca..2de47b0 100644 --- a/bdshemu/bdshemu.c +++ b/bdshemu/bdshemu.c @@ -1187,82 +1187,89 @@ ShemuGetOperandValue( else if (op->Type == ND_OP_MEM) { uint64_t gla = ShemuComputeLinearAddress(Context, op); + uint32_t offset; + uint8_t seg; if (op->Info.Memory.IsAG) { // Address generation instruction, the result is the linear address itself. Value->Value.Qwords[0] = gla; + goto done_gla; + } + + if (Context->Ring == 3) + { + // User-mode TIB offset that contains the PEB address. + offset = Context->Mode == ND_CODE_32 ? 0x30 : 0x60; + seg = Context->Mode == ND_CODE_32 ? ND_PREFIX_G2_SEG_FS : ND_PREFIX_G2_SEG_GS; } else { - uint32_t offset; - uint8_t seg; + // Kernel-mode KPCR offset that contains the current KTHREAD address. + offset = Context->Mode == ND_CODE_32 ? 0x124 : 0x188; + seg = Context->Mode == ND_CODE_32 ? ND_PREFIX_G2_SEG_FS : ND_PREFIX_G2_SEG_GS; + } - if (Context->Ring == 3) - { - // User-mode TIB offset that contains the PEB address. - offset = Context->Mode == ND_CODE_32 ? 0x30 : 0x60; - seg = Context->Mode == ND_CODE_32 ? ND_PREFIX_G2_SEG_FS : ND_PREFIX_G2_SEG_GS; - } - else - { - // Kernel-mode KPCR offset that contains the current KTHREAD address. - offset = Context->Mode == ND_CODE_32 ? 0x124 : 0x188; - seg = Context->Mode == ND_CODE_32 ? ND_PREFIX_G2_SEG_FS : ND_PREFIX_G2_SEG_GS; - } + // Check if this is a TIB/PCR access. Make sure the FS/GS register is used for the access, in order to avoid + // false positives where legitimate code accesses a linear TIB directly. + // Note that this covers accesses to the PEB field inside the TIB. + if (gla == Context->TibBase + offset && Context->Instruction.Seg == seg) + { + Context->Flags |= SHEMU_FLAG_TIB_ACCESS; + } - // Check if this is a TIB/PCR access. Make sure the FS/GS register is used for the access, in order to avoid - // false positives where legitimate code accesses a linear TIB directly. - // Note that this covers accesses to the PEB field inside the TIB. - if (gla == Context->TibBase + offset && Context->Instruction.Seg == seg) - { - Context->Flags |= SHEMU_FLAG_TIB_ACCESS; - } + // Note that this covers accesses to the Wow32Reserved in Wow64 mode. That field can be used to issue + // syscalls. + if (gla == Context->TibBase + 0xC0 && Context->Instruction.Seg == seg && Context->Mode == ND_CODE_32) + { + Context->Flags |= SHEMU_FLAG_TIB_ACCESS_WOW32; + } - // Note that this covers accesses to the Wow32Reserved in Wow64 mode. That field can be used to issue - // syscalls. - if (gla == Context->TibBase + 0xC0 && Context->Instruction.Seg == seg && Context->Mode == ND_CODE_32) - { - Context->Flags |= SHEMU_FLAG_TIB_ACCESS_WOW32; - } + // Check for accesses inside the KUSER_SHARED_DATA (SharedUserData). This page contains some + // global system information, it may host shellcodes, and is hard-coded at this address. + if (gla >= 0x7FFE0000 && gla < 0x7FFE1000) + { + Context->Flags |= SHEMU_FLAG_SUD_ACCESS; + } - // Check if we are reading a previously saved RIP. Ignore RET category, which naturally uses the saved RIP. - // Also, ignore RMW instruction which naturally read the current value - this could happen if the code - // modifies the return value, for example "ADD qword [rsp], r8". - if (Context->Instruction.Category != ND_CAT_RET && !(op->Access.Access & ND_ACCESS_ANY_WRITE) && - ShemuIsStackPtr(Context, gla, op->Size) && - ShemuAnyBitsSet(STACKBMP(Context), gla - Context->StackBase, op->Size)) - { - Context->Flags |= SHEMU_FLAG_LOAD_RIP; - } + // Check if we are reading a previously saved RIP. Ignore RET category, which naturally uses the saved RIP. + // Also, ignore RMW instruction which naturally read the current value - this could happen if the code + // modifies the return value, for example "ADD qword [rsp], r8". + if (Context->Instruction.Category != ND_CAT_RET && !(op->Access.Access & ND_ACCESS_ANY_WRITE) && + ShemuIsStackPtr(Context, gla, op->Size) && + ShemuAnyBitsSet(STACKBMP(Context), gla - Context->StackBase, op->Size)) + { + Context->Flags |= SHEMU_FLAG_LOAD_RIP; + } - // Get the memory value. - status = ShemuGetMemValue(Context, gla, Value->Size, Value->Value.Bytes); - if (SHEMU_SUCCESS != status) - { - return status; - } + // Get the memory value. + status = ShemuGetMemValue(Context, gla, Value->Size, Value->Value.Bytes); + if (SHEMU_SUCCESS != status) + { + return status; + } - // If this is a stack access, we need to update the stack pointer. - if (op->Info.Memory.IsStack) - { - uint64_t regval = ShemuGetGprValue(Context, NDR_RSP, (2 << Context->Instruction.DefStack), false); + // If this is a stack access, we need to update the stack pointer. + if (op->Info.Memory.IsStack) + { + uint64_t regval = ShemuGetGprValue(Context, NDR_RSP, (2 << Context->Instruction.DefStack), false); - regval += op->Size; + regval += op->Size; - ShemuSetGprValue(Context, NDR_RSP, (2 << Context->Instruction.DefStack), regval, false); - } + ShemuSetGprValue(Context, NDR_RSP, (2 << Context->Instruction.DefStack), regval, false); + } - // If this is a string operation, make sure we update RSI/RDI. - if (op->Info.Memory.IsString) - { - uint64_t regval = ShemuGetGprValue(Context, op->Info.Memory.Base, op->Info.Memory.BaseSize, false); + // If this is a string operation, make sure we update RSI/RDI. + if (op->Info.Memory.IsString) + { + uint64_t regval = ShemuGetGprValue(Context, op->Info.Memory.Base, op->Info.Memory.BaseSize, false); - regval = GET_FLAG(Context, NDR_RFLAG_DF) ? regval - op->Size : regval + op->Size; + regval = GET_FLAG(Context, NDR_RFLAG_DF) ? regval - op->Size : regval + op->Size; - ShemuSetGprValue(Context, op->Info.Memory.Base, op->Info.Memory.BaseSize, regval, false); - } + ShemuSetGprValue(Context, op->Info.Memory.Base, op->Info.Memory.BaseSize, regval, false); } + +done_gla:; } else if (op->Type == ND_OP_IMM) { @@ -2414,7 +2421,7 @@ check_far_branch: } // We may, in the future, emulate far branches, but they imply some tricky context switches (including - // the default TEB), so it may not be as straight forward as it seems. For now, al we wish to achieve + // the default TEB), so it may not be as straight forward as it seems. For now, all we wish to achieve // is detection of far branches in long-mode, from Wow 64. stop = true; break; diff --git a/bdshemu_test/bdshemu_test.zip b/bdshemu_test/bdshemu_test.zip index fcddd80..300fbc5 100644 Binary files a/bdshemu_test/bdshemu_test.zip and b/bdshemu_test/bdshemu_test.zip differ diff --git a/disasmtool/disasmtool.c b/disasmtool/disasmtool.c index d450394..c5d03fb 100644 --- a/disasmtool/disasmtool.c +++ b/disasmtool/disasmtool.c @@ -1673,6 +1673,10 @@ handle_shemu( { printf(" SHEMU_FLAG_STACK_PIVOT\n"); } + if (ctx.Flags & SHEMU_FLAG_SUD_ACCESS) + { + printf(" SHEMU_FLAG_SUD_ACCESS\n"); + } if (ctx.Flags & SHEMU_FLAG_KPCR_ACCESS) { printf(" SHEMU_FLAG_KPCR_ACCESS\n"); diff --git a/inc/bdshemu.h b/inc/bdshemu.h index 7b48850..7a57047 100644 --- a/inc/bdshemu.h +++ b/inc/bdshemu.h @@ -254,6 +254,7 @@ typedef unsigned int SHEMU_STATUS; #define SHEMU_FLAG_TIB_ACCESS_WOW32 0x00000040 // The code accesses the Wow32Reserved field inside TIB. #define SHEMU_FLAG_HEAVENS_GATE 0x00000080 // The code uses Heaven's gate to switch into 64 bit mode. #define SHEMU_FLAG_STACK_PIVOT 0x00000100 // The code switched the stack using XCHG esp, *. +#define SHEMU_FLAG_SUD_ACCESS 0x00000200 // The code accesses the KUSER_SHARED_DATA page. // Kernel specific flags. #define SHEMU_FLAG_KPCR_ACCESS 0x00010000 // KPCR current thread access via gs:[0x188]/fs:[0x124]. #define SHEMU_FLAG_SWAPGS 0x00020000 // SWAPGS was executed. diff --git a/inc/version.h b/inc/version.h index 4060e9b..9da0e7c 100644 --- a/inc/version.h +++ b/inc/version.h @@ -7,6 +7,6 @@ #define DISASM_VERSION_MAJOR 1 #define DISASM_VERSION_MINOR 34 -#define DISASM_VERSION_REVISION 1 +#define DISASM_VERSION_REVISION 2 #endif // DISASM_VER_H diff --git a/pybddisasm/setup.py b/pybddisasm/setup.py index 1a5abd4..969ffc5 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, 34, 1) +LIBRARY_VERSION = (1, 34, 2) LIBRARY_INSTRUX_SIZE = 864 packages = ['pybddisasm']