Compare commits

..

No commits in common. 'ba14104087acc65ebca806ba15e8a680fcbd505c' and '727c87ecc44a9035ca01e68a213d8460ee2aecd2' have entirely different histories.

@ -143,6 +143,6 @@ jobs:
run: sudo apt install -y cppcheck
- name: Run cppcheck
run: cppcheck --error-exitcode=1 --language=c \
--enable=all --suppress=missingIncludeSystem --suppress=unusedStructMember --suppress=unusedFunction --suppress=objectIndex \
--enable=all --suppress=missingIncludeSystem --suppress=unusedStructMember --suppress=unusedFunction \
-I inc/ -I bddisasm/include bddisasm/ bdshemu/ \
/

8
.gitignore vendored

@ -57,9 +57,7 @@ compile_commands.json
pydis/.eggs
bdshemu_fuzz/out
bdshemu_fuzz/shfuzz
bdshemu_fuzz/in-32
bdshemu_fuzz/out-32
bdshemu_fuzz/in-64
bdshemu_fuzz/out-64
docs/build
libbddisasm.pc
@ -69,9 +67,3 @@ disasmtool_lix/_build
bindings/rsbddisasm/target
bindings/rsbddisasm/Cargo.lock
bindings/pybddisasm/pybddisasm.egg-info
bindings/rsbddisasm/bddisasm/target
bindings/pybddisasm/pybddisasm/pybddisasm.py
bindings/pybddisasm/pybddisasm/pybddisasm_wrap.c
bddfuzz.tar
bindings/pybddisasm/.eggs

@ -1,54 +0,0 @@
# Changelog
All notable (user-facing) changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [2.1.0] - 2024-02-20
### Added
- Support in bddisasm for Intel REX2 prefix.
- Support in bddisasm for Intel APX extensions.
- Support in bddisasm for Intel USERMSR extensions.
- Support in bddisasm for prefix activation fields inside `INSTRUX` - these fields can be consulted to determine whether a particular prefix is present, accepted & active.
- New feature in bdshemu: `SHEMU_OPT_DIRECT_MAPPED_SHELL` - allows emulation with a smaller `IntBuff` at the cost of not having `WRITE_SELF` detections. The shellcode can be provided directly from its original location, without the need to allocate it in a dedicated memory region.
- New feature in bdshemu: `SHEMU_OPT_TRACK_LOOPS` - loops can now be tracked by bdshemu. `SHEMU_OPT_TRACE_LOOPS` can be used to log loop information.
- Support in bdshemu for APX instructions (both REX2 and EVEX encoded instructions) - the new `SHEMU_OPT_SUPPORT_APX` must be set in order to enable APX emulation.
### Changed
- Reduced the size of the `INSTRUX` structure from 856 bytes to 488 bytes (almost -43%!).
- Increased decoding performance from average 300 clocks/instruction to average 235 clocks/instruction (almost +20%!).
- New decode options - do not decode implicit operands - this further increases performance from average 235 clocks/instruction to 200 clocks/instruction (almost +15%!).
- Re-worked the Python scripts - both `disasmlib.py` and `generate_tables.py` have been significantly reworked, improving readability, and making them more efficient.
- `disasmtool` builds on Linux.
### Removed
- Support for Cyrix & VIA instructions - only current Intel & AMD instructions remain supported.
- disasmtool_lix has been removed. `disasmtool` is available on Linux as well.
### Breaking changes
#### Inside INSTRUX
- Removed `Iclass` field - it was aliased over `Instruction` field, which must be used from now on.
- Removed `OperandsEncodingMap` field - one can consult the `Encoding` field in each operand to determine the encoding.
- Removed `ExceptionClass` field - only `ExceptionType` remains, which contains an enum with all the exception types.
- Removed `Predicate` field - only `Condition` remains, which was aliased over `Predicate`.
- Removed `HasImm3`, `Immediate3`, `Imm3Length` and `Imm3Offset` fields, as they were not used/needed.
- Removed `Bhint`, `SseCondition`, `SignDisp` fields, as they were not used.
- Moved `FlagsAccess.RegAccess` outside and renamed it to `RflAccess`, to save more space.
- Switched from `char Mnemonic[32]` to `const char *Mnemonic` - this decreases INSTRUX size by almost 32 bytes, and increases perf.
#### Inside ND_OPERAND
- Removed `RawSize` - in most cases, `Size` and `RawSize` are identical; the only case where they might differ is for `Immediate` and `RelativeOffset` operands - in that case, one can consult the `RawSize` field in `Immediate` or `RelativeOffset`.
#### Inside ND_OPERAND_DECORATOR
- Removed `Broadcast` field, moved it inside `ND_OPDESC_MEMORY`.
- Removed `HasSae`, `HasEr` - they are per instruction, not per operand, and can be consulted directly inside `INSTRUX`.
- Moved `Msk` one level up, inside the `ND_OPERAND_DECORATOR` structure.
#### Defines & constants
- Removed `ND_PRED_*` defines - search & replace them with `ND_COND_*`.
- Removed `ND_HAS_PREDICATE` - use `ND_HAS_CONDITION` instead.
- Removed `ND_VEND_GEODE` and `ND_VEND_CYRIX`.

@ -1,18 +1,16 @@
cmake_minimum_required(VERSION 3.16)
option(BDD_INCLUDE_TOOL "Include the disasmtool executable" ON)
option(BDD_INCLUDE_ISAGENERATOR_X86 "Include the x86 isagenerator target (if a python interpreter is found)" ON)
option(BDD_INCLUDE_ISAGENERATOR "Include the isagenerator target (if a python interpreter is found)" ON)
option(BDD_INCLUDE_FUZZERS "Include the bdshemu fuzzer" OFF)
option(BDD_USE_EXTERNAL_VSNPRINTF "Expect nd_vsnprintf_s implementation from the integrator" OFF)
option(BDD_USE_EXTERNAL_MEMSET "Expect nd_memset implementation from the integrator" OFF)
option(BDD_ASAN "Build with ASAN" OFF)
option(BDD_UBSAN "Build with UBSAN" OFF)
set(BDD_VER_FILE ${CMAKE_CURRENT_LIST_DIR}/inc/bddisasm_version.h)
set(BDD_VER_FILE ${CMAKE_CURRENT_LIST_DIR}/inc/version.h)
file(STRINGS ${BDD_VER_FILE} disasm_ver_major REGEX "#define DISASM_VERSION_MAJOR")
file(STRINGS ${BDD_VER_FILE} disasm_ver_minor REGEX "#define DISASM_VERSION_MINOR")
file(STRINGS ${BDD_VER_FILE} disasm_ver_patch REGEX "#define DISASM_VERSION_REVISION")
file(STRINGS ${BDD_VER_FILE} disasm_ver_major REGEX "DISASM_VERSION_MAJOR")
file(STRINGS ${BDD_VER_FILE} disasm_ver_minor REGEX "DISASM_VERSION_MINOR")
file(STRINGS ${BDD_VER_FILE} disasm_ver_patch REGEX "DISASM_VERSION_REVISION")
string(REGEX REPLACE "#define DISASM_VERSION_MAJOR[ \t\r\n]*" "" disasm_ver_major ${disasm_ver_major})
string(REGEX REPLACE "#define DISASM_VERSION_MINOR[ \t\r\n]*" "" disasm_ver_minor ${disasm_ver_minor})
@ -27,7 +25,7 @@ project(
LANGUAGES C
HOMEPAGE_URL https://github.com/bitdefender/bddisasm)
# Use Release as the build type if no build type was specified and we're not using a multi-config generator.
# Use Release as the build type if no build type was specified and we're not using a multi-config generator .
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "No build type given. Will use 'Release'")
set(CMAKE_BUILD_TYPE
@ -81,17 +79,12 @@ endif ()
set(BDDISASM_PUBLIC_HEADERS
"inc/bddisasm.h"
"inc/bddisasm_status.h"
"inc/bddisasm_types.h"
"inc/bddisasm_version.h"
"inc/bdx86_constants.h"
"inc/bdx86_core.h"
"inc/bdx86_cpuidflags.h"
"inc/bdx86_registers.h")
set(BDSHEMU_PUBLIC_HEADERS
"inc/bdshemu_x86.h"
"inc/bdshemu.h")
"inc/constants.h"
"inc/cpuidflags.h"
"inc/disasmstatus.h"
"inc/disasmtypes.h"
"inc/registers.h"
"inc/version.h")
include(GNUInstallDirs)
@ -107,20 +100,20 @@ include(CheckCCompilerFlag)
add_library(
bddisasm STATIC
bddisasm/bddisasm_crt.c
bddisasm/bdx86_decoder.c
bddisasm/bdx86_formatter.c
bddisasm/bdx86_helpers.c
bddisasm/crt.c
bddisasm/bddisasm.c
bddisasm/bdformat.c
bddisasm/bdhelpers.c
# Add the headers so they will show up in IDEs.
bddisasm/include/bddisasm_crt.h
bddisasm/include/bdx86_instructions.h
bddisasm/include/bdx86_mnemonics.h
bddisasm/include/bdx86_prefixes.h
bddisasm/include/bdx86_tabledefs.h
bddisasm/include/bdx86_table_evex.h
bddisasm/include/bdx86_table_root.h
bddisasm/include/bdx86_table_vex.h
bddisasm/include/bdx86_table_xop.h
bddisasm/include/instructions.h
bddisasm/include/mnemonics.h
bddisasm/include/nd_crt.h
bddisasm/include/prefixes.h
bddisasm/include/table_evex.h
bddisasm/include/table_root.h
bddisasm/include/table_vex.h
bddisasm/include/table_xop.h
bddisasm/include/tabledefs.h
"${BDDISASM_PUBLIC_HEADERS}")
if (NOT BDD_USE_EXTERNAL_VSNPRINTF)
@ -161,20 +154,6 @@ set_target_properties(
VERSION ${CMAKE_PROJECT_VERSION}
SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR})
if (BDD_ASAN)
target_compile_options(bddisasm PUBLIC "-fsanitize=address")
target_link_libraries(bddisasm PUBLIC "-fsanitize=address")
endif ()
if (BDD_UBSAN)
target_compile_options(bddisasm PUBLIC
"-fsanitize=undefined"
"-fno-sanitize=alignment")
target_link_libraries(bddisasm PUBLIC
"-fsanitize=undefined"
"-fno-sanitize=alignment")
endif ()
add_library(bddisasm::bddisasm ALIAS bddisasm)
# -- bdshemu --
@ -182,10 +161,8 @@ add_library(bddisasm::bddisasm ALIAS bddisasm)
add_library(
bdshemu STATIC
bdshemu/bdshemu.c
bdshemu/bdshemu_x86.c
# Add the headers so they will show up in IDEs.
bdshemu/include/bdshemu_common.h
"${BDSHEMU_PUBLIC_HEADERS}")
inc/bdshemu.h)
set_target_properties(
bdshemu
@ -208,7 +185,7 @@ endif ()
set_target_properties(
bdshemu
PROPERTIES PUBLIC_HEADER "${BDSHEMU_PUBLIC_HEADERS}"
PROPERTIES PUBLIC_HEADER "inc/bdshemu.h"
VERSION ${CMAKE_PROJECT_VERSION}
SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR})
@ -216,14 +193,19 @@ add_library(bddisasm::bdshemu ALIAS bdshemu)
# If this is the master project (and if the user requested it) add disasmtool.
if ((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) AND BDD_INCLUDE_TOOL)
add_subdirectory(disasmtool)
if (WIN32)
add_subdirectory(disasmtool)
else ()
add_subdirectory(disasmtool_lix)
endif ()
endif ()
# If this is the master project (and if the user requested it) add isagenerator.
if ((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) AND BDD_INCLUDE_ISAGENERATOR_X86)
if ((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) AND BDD_INCLUDE_ISAGENERATOR)
add_subdirectory(isagenerator)
endif ()
# If this is the master project (and if the user requested it) add the fuzzer.
if ((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) AND BDD_INCLUDE_FUZZERS)
add_subdirectory(bdshemu_fuzz)
endif ()
@ -254,7 +236,7 @@ if (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
COMPONENT bddisasm_Runtime
NAMELINK_COMPONENT bddisasm_Development
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT bddisasm_Development)
if (BDD_INCLUDE_TOOL)
install(
TARGETS disasmtool

@ -1,118 +0,0 @@
FROM ubuntu:22.04 as build
WORKDIR /bddfuzz
# Install everything we need to build AFL++ and honggfuzz and bdshemu
# We install both clang-13 and clang-15 because honggfuzz does not support newer versions of clang, but AFL++ wants
# the latest version so it is what it is
RUN apt-get update && apt-get install -y \
cmake make git \
binutils-dev \
libunwind-dev \
libblocksruntime-dev \
clang-13 \
clang-15 \
llvm-15 llvm-15-dev llvm-15-linker-tools llvm-15-runtime llvm-15-tools lld-15
# Cleanup
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
RUN mkdir /bddfuzz/fuzzers
# Build and install AFL++
RUN cd /bddfuzz/fuzzers && git clone https://github.com/AFLplusplus/AFLplusplus.git
RUN cd /bddfuzz/fuzzers/AFLplusplus && \
CC=clang-15 CXX=clang++-15 make source-only install LLVM_CONFIG=llvm-config-15 NO_NYX=1
# Build and install honggfuzz
RUN cd /bddfuzz/fuzzers && git clone --depth 1 --branch 2.5 https://github.com/google/honggfuzz.git
RUN cd /bddfuzz/fuzzers/honggfuzz && make install
# Remove the fuzzer source files as we no longer need them
RUN cd /bddfuzz/fuzzers/AFLplusplus && git clean -dxf && git clean -dXf && rm -rf /bddfuzz/fuzzers/AFLplusplus
RUN rm -rf /bddfuzz/fuzzers/honggfuzz
RUN rm -rf /bddfuzz/fuzzers/
ENV SRC /bddfuzz/src/
# Copy the relevant bddisasm sources
RUN mkdir "${SRC}"
COPY CMakeLists.txt "${SRC}"/CMakeLists.txt
COPY bddisasm.pc.in "${SRC}"/bddisasm.pc.in
COPY bddisasmConfig.cmake "${SRC}"/bddisasmConfig.cmake
COPY bddisasm "${SRC}"/bddisasm
COPY bdshemu "${SRC}"/bdshemu
COPY bdshemu_fuzz "${SRC}"/bdshemu_fuzz
COPY inc "${SRC}"/inc
# Now build all the variants
RUN mkdir build
# Build for AFL++ with afl-clang-lto
RUN mkdir /bddfuzz/build/afllto && cd /bddfuzz/build/afllto && \
cmake "${SRC}" -DCMAKE_C_COMPILER=afl-clang-lto -DCMAKE_CXX_COMPILER=afl-clang-lto++ \
-DCMAKE_BUILD_TYPE=Releaase \
-DBDD_INCLUDE_TOOL=OFF -DBDD_INCLUDE_ISAGENERATOR_X86=OFF \
-DBDD_INCLUDE_FUZZERS=ON && \
make shfuzz
# Build for honggfuzz
RUN mkdir /bddfuzz/build/hfuzz && cd /bddfuzz/build/hfuzz && \
cmake "${SRC}" -DCMAKE_C_COMPILER=hfuzz-clang -DCMAKE_CXX_COMPILER=hfuzz-clang++ \
-DCMAKE_BUILD_TYPE=Releaase \
-DBDD_INCLUDE_TOOL=OFF -DBDD_INCLUDE_ISAGENERATOR_X86=OFF \
-DBDD_INCLUDE_FUZZERS=ON && \
make shfuzz
# Build for libfuzzer with ASAN and UBSAN
RUN mkdir /bddfuzz/build/san && cd /bddfuzz/build/san && \
cmake "${SRC}" -DCMAKE_C_COMPILER=clang-15 -DCMAKE_CXX_COMPILER=clang-15++ \
-DCMAKE_BUILD_TYPE=Releaase \
-DBDD_INCLUDE_TOOL=OFF -DBDD_INCLUDE_ISAGENERATOR_X86=OFF \
-DBDD_INCLUDE_FUZZERS=ON -DBDD_FUZZ_WITH_LOGS=ON \
-DBDD_ASAN=ON -DBDD_UBSAN=ON && \
make shfuzz
RUN rm -rf "${SRC}"
# Save the fuzzers
RUN mkdir /bddfuzz/shf && cd /bddfuzz/shf && \
for d in /bddfuzz/build/*; do \
mkdir ./`basename "${d}"` && \
cp -v "${d}"/bdshemu_fuzz/shfuzz* ./`basename "${d}"`; \
done
# Remove the build directory
RUN rm -rf build
FROM ubuntu:22.04 as run
WORKDIR /bddfuzz
# Copy the fuzzers from the build stage
COPY --from=build /bddfuzz/shf /bddfuzz/shf
# Copy AFL++ and honggfuzz binaries
COPY --from=build /usr/local/bin/afl-* /usr/local/bin/
COPY --from=build /usr/local/bin/hfuzz-* /usr/local/bin/
COPY --from=build /usr/local/bin/honggfuzz /usr/local/bin/
RUN mkdir /bddfuzz/inputs
COPY bdshemu_fuzz/in-32 /bddfuzz/inputs/in-32
COPY bdshemu_fuzz/in-64 /bddfuzz/inputs/in-64
# Runtime dependencies for honggfuzz
RUN apt-get update && apt-get install -y binutils-dev libunwind-dev libblocksruntime-dev
# Cleanup
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# So we can share files between the host and the container (we don't want to loose the results when we stop the
# container).
ENV SHARE_DIR share
COPY bdshemu_fuzz/fuzzing_image_entrypoint.sh /bddfuzz/fuzzing_image_entrypoint.sh
RUN chmod +x /bddfuzz/fuzzing_image_entrypoint.sh
ENTRYPOINT ["/bddfuzz/fuzzing_image_entrypoint.sh"]

@ -5,10 +5,12 @@ The Bitdefender disassembler (bddisasm) is a lightweight, x86/x64 only instructi
## Projects
1. [bddisasm](https://github.com/bitdefender/bddisasm/tree/master/bddisasm) - this is the main disassembler project. In order to use the Bitdefender disassembler, all you have to do is build this project, and link with the output library. The only headers you need are located inside the `inc` folder.
2. [bdshemu](https://github.com/bitdefender/bddisasm/tree/master/bdshemu) - this project makes use of the main bddisasm lib in order to build a simple, lightweight, fast, instructions emulator, designated to target shellcodes. This project is also integrated inside the disasmtool, so you can emulate raw binary files, and see their output. Note that this simple emulator supports basic x86/x64 instructions, and does not support emulating any kind of API call. In addition, the only supported memory accesses are inside the shellcode itself, and on the emulated stack.
3. [isagenerator_x86](https://github.com/bitdefender/bddisasm/tree/master/isagenerator) - this project contains the instruction definitions and the scripts required to generate the disassembly tables. If you wish to add support for a new instruction, this is the place. This project will automatically generate several header files (instructions.h, mnemonics.h, constants.h, table_\*.h), so please make sure you don't manually edit any of these files. You will need Python 3 to run the generation scripts.
2. [bdshemu](https://github.com/bitdefender/bddisasm/tree/master/bdshemu) - this project makes use of the main bddisasm lib in order to build a simple, lightweight, fast, instructions emulator, designated to target shellcodes. This project is also integrated inside the disasmtool, so you can
emulate raw binary files, and see their output. Note that this simple emulator supports basic x86/x64 instructions, and does not support emulating any kind of API call. In addition, the only supported memory accesses are inside the shellcode itself, and on the emulated stack.
3. [isagenerator](https://github.com/bitdefender/bddisasm/tree/master/isagenerator) - this project contains the instruction definitions and the scripts required to generate the disassembly tables. If you wish to add support for a new instruction, this is the place. This project will automatically generate several header files (instructions.h, mnemonics.h, constants.h, table_\*.h), so please make sure you don't manually edit any of these files. You will need Python 3 to run the generation scripts.
4. [disasmtool](https://github.com/bitdefender/bddisasm/tree/master/disasmtool) - this project is a command line disassembler tool, used mainly as an example of how to integrate the bddisasm and bdshemu libraries.
5. [bindings](https://github.com/bitdefender/bddisasm/tree/master/bindings) - bindings for [python](https://github.com/bitdefender/bddisasm/tree/master/bindings/pybddisasm), and [Rust](https://github.com/bitdefender/bddisasm/tree/master/bindings/rsbddisasm).
5. [disasmtool_lix](https://github.com/bitdefender/bddisasm/tree/master/disasmtool_lix) - like disasmtool, but for Linux.
6. [bindings](https://github.com/bitdefender/bddisasm/tree/master/bindings) - bindings for [python](https://github.com/bitdefender/bddisasm/tree/master/bindings/pybddisasm), and [Rust](https://github.com/bitdefender/bddisasm/tree/master/bindings/rsbddisasm).
## Objectives
@ -159,13 +161,13 @@ The results will be in the bin directory in the root of the repository.
[nd_vsnprintf_s and nd_memset](#nd_vsnprintf_s-and-nd_memset) will not be defined by `bddisasm`, integrators must provide these functions.
## Decoding x86 instructions
## Decoding instructions
### Decoding API
There are 4 decoding functions, but internally, they all do the same, albeit some of them with implicit arguments:
- `NDSTATUS NdDecode(INSTRUX *Instrux, const uint8_t *Code, uint8_t DefCode, uint8_t DefData)` - this API should be used only if you don't care about the length of the input buffer;
- `NDSTATUS NdDecode(INSTRUX *Instrux, const uint8_t *Code, uint8_t DefCode, uint8_t DefData)` - this API should be used only if you don't care about the length of the input buffer;
- `NDSTATUS NdDecodeEx(INSTRUX *Instrux, const uint8_t *Code, size_t Size, uint8_t DefCode, uint8_t DefData);` - decode instruction from a buffer with maximum length `Size`;
- `NDSTATUS NdDecodeEx2(INSTRUX *Instrux, const uint8_t *Code, size_t Size, uint8_t DefCode, uint8_t DefData, uint8_t DefStack, uint8_t PreferedVendor);` - decode instructions with a preferred vendor;
- `NDSTATUS NdDecodeWithContext(INSTRUX *Instrux, const uint8_t *Code, size_t Size, ND_CONTEXT *Context);` - base decode API; the input parameters - `DefCode`, `DefData`, `DefStack`, `VendMode` and `FeatMode` must all be filled in the `Context` structure before calling this function. The Context structure should also be initialized using `NdInitContext` before the first decode call.
@ -275,10 +277,10 @@ Working with the extended API is also trivial:
INSTRUX ix;
ND_CONTEXT ctx;
uint8_t code[] = { 0x48, 0x8B, 0x48, 0x28 };
// This has to be done only once.
NdInitContext(&ctx);
ctx.DefCode = ND_CODE_64;
ctx.DefData = ND_DATA_64;
ctx.DefStack = ND_STACK_64;

@ -15,11 +15,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bdshemu", "bdshemu\bdshemu.
{3653AA19-048B-410E-B5C4-FF78E1D84C12} = {3653AA19-048B-410E-B5C4-FF78E1D84C12}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "isagenerator_x86", "isagenerator\isagenerator.vcxproj", "{0E9D2957-34FA-40EE-B4B2-0D008D2FE317}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{3114F0D4-BEBA-4574-A349-D03477C64C60}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{1F8BBB39-7787-4A50-8170-27EB5FA104D0}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "isagenerator", "isagenerator\isagenerator.vcxproj", "{0E9D2957-34FA-40EE-B4B2-0D008D2FE317}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -89,12 +85,6 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{94F1B65D-3305-4CCB-9DF1-50B56900D867} = {1F8BBB39-7787-4A50-8170-27EB5FA104D0}
{3653AA19-048B-410E-B5C4-FF78E1D84C12} = {3114F0D4-BEBA-4574-A349-D03477C64C60}
{3C9B2CA7-CF4F-471B-BB72-6490C476CDCA} = {3114F0D4-BEBA-4574-A349-D03477C64C60}
{0E9D2957-34FA-40EE-B4B2-0D008D2FE317} = {3114F0D4-BEBA-4574-A349-D03477C64C60}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E950FA16-07C1-4613-8328-906BC10C7C02}
EndGlobalSection

@ -1,6 +1,6 @@
.PHONY: clean
SRC_FILES := bddisasm_crt.c bdx86_decoder.c bdx86_formatter.c bdx86_helpers.c
SRC_FILES := crt.c bddisasm.c bdformat.c bdhelpers.c
OBJECTS := $(SRC_FILES:.c=.o)

File diff suppressed because it is too large Load Diff

@ -115,8 +115,7 @@
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<TargetVersion>
</TargetVersion>
<TargetVersion></TargetVersion>
<DriverTargetPlatform>Desktop</DriverTargetPlatform>
<SupportsPackaging>false</SupportsPackaging>
<ALLOW_DATE_TIME>1</ALLOW_DATE_TIME>
@ -144,8 +143,7 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<TargetVersion>
</TargetVersion>
<TargetVersion></TargetVersion>
<DriverTargetPlatform>Desktop</DriverTargetPlatform>
<SupportsPackaging>false</SupportsPackaging>
<ALLOW_DATE_TIME>1</ALLOW_DATE_TIME>
@ -645,10 +643,10 @@
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="bdx86_formatter.c" />
<ClCompile Include="bdx86_helpers.c" />
<ClCompile Include="bddisasm_crt.c" />
<ClCompile Include="bdx86_decoder.c">
<ClCompile Include="bdformat.c" />
<ClCompile Include="bdhelpers.c" />
<ClCompile Include="crt.c" />
<ClCompile Include="bddisasm.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseKernel|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseKernel|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseKernel|ARM64'">NotUsing</PrecompiledHeader>
@ -667,23 +665,22 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\inc\bdx86_core.h" />
<ClInclude Include="..\inc\bdx86_constants.h" />
<ClInclude Include="..\inc\bdx86_cpuidflags.h" />
<ClInclude Include="..\inc\constants.h" />
<ClInclude Include="..\inc\cpuidflags.h" />
<ClInclude Include="..\inc\bddisasm.h" />
<ClInclude Include="..\inc\bddisasm_status.h" />
<ClInclude Include="..\inc\bddisasm_types.h" />
<ClInclude Include="..\inc\bdx86_registers.h" />
<ClInclude Include="..\inc\bddisasm_version.h" />
<ClInclude Include="include\bdx86_instructions.h" />
<ClInclude Include="include\bdx86_mnemonics.h" />
<ClInclude Include="include\bddisasm_crt.h" />
<ClInclude Include="include\bdx86_prefixes.h" />
<ClInclude Include="include\bdx86_tabledefs.h" />
<ClInclude Include="include\bdx86_table_evex.h" />
<ClInclude Include="include\bdx86_table_root.h" />
<ClInclude Include="include\bdx86_table_vex.h" />
<ClInclude Include="include\bdx86_table_xop.h" />
<ClInclude Include="..\inc\disasmstatus.h" />
<ClInclude Include="..\inc\disasmtypes.h" />
<ClInclude Include="..\inc\registers.h" />
<ClInclude Include="..\inc\version.h" />
<ClInclude Include="include\instructions.h" />
<ClInclude Include="include\mnemonics.h" />
<ClInclude Include="include\nd_crt.h" />
<ClInclude Include="include\prefixes.h" />
<ClInclude Include="include\tabledefs.h" />
<ClInclude Include="include\table_evex.h" />
<ClInclude Include="include\table_root.h" />
<ClInclude Include="include\table_vex.h" />
<ClInclude Include="include\table_xop.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

@ -19,87 +19,69 @@
<Filter Include="Other">
<UniqueIdentifier>{5e26c505-e8f5-4e6c-9d54-f20e36b637b8}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\x86">
<UniqueIdentifier>{39065bbd-3fd0-42b0-ba8e-d7395674b7ce}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\public\x86">
<UniqueIdentifier>{032f0e51-6265-4031-b702-5eb620d95964}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\private">
<UniqueIdentifier>{5eb8f135-5960-4e0e-a5a8-5214a7a9edcb}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\private\x86">
<UniqueIdentifier>{db15a655-cc99-4e12-a8c3-55a485ee713c}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\private\x86\tables">
<UniqueIdentifier>{b9961460-d06f-4288-9708-44ca965c4a0d}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="bddisasm_crt.c">
<ClCompile Include="crt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bdx86_decoder.c">
<Filter>Source Files\x86</Filter>
<ClCompile Include="bddisasm.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bdx86_formatter.c">
<Filter>Source Files\x86</Filter>
<ClCompile Include="bdformat.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bdx86_helpers.c">
<Filter>Source Files\x86</Filter>
<ClCompile Include="bdhelpers.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\inc\bddisasm_version.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="include\instructions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\bdx86_constants.h">
<Filter>Header Files\public\x86</Filter>
<ClInclude Include="include\mnemonics.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\bdx86_cpuidflags.h">
<Filter>Header Files\public\x86</Filter>
</ClInclude>
<ClInclude Include="..\inc\bddisasm_types.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="include\prefixes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\bdx86_registers.h">
<Filter>Header Files\public\x86</Filter>
<ClInclude Include="include\table_evex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\bddisasm_status.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="include\table_root.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\bddisasm.h">
<Filter>Header Files\public</Filter>
<ClInclude Include="include\table_vex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\bdx86_core.h">
<Filter>Header Files\public\x86</Filter>
<ClInclude Include="include\table_xop.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_instructions.h">
<Filter>Header Files\private\x86</Filter>
<ClInclude Include="include\tabledefs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_mnemonics.h">
<Filter>Header Files\private\x86</Filter>
<ClInclude Include="..\inc\constants.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_prefixes.h">
<Filter>Header Files\private\x86</Filter>
<ClInclude Include="..\inc\bddisasm.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_tabledefs.h">
<Filter>Header Files\private\x86</Filter>
<ClInclude Include="..\inc\disasmstatus.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\bddisasm_crt.h">
<Filter>Header Files\private</Filter>
<ClInclude Include="..\inc\disasmtypes.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_table_evex.h">
<Filter>Header Files\private\x86\tables</Filter>
<ClInclude Include="..\inc\registers.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_table_root.h">
<Filter>Header Files\private\x86\tables</Filter>
<ClInclude Include="..\inc\version.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_table_vex.h">
<Filter>Header Files\private\x86\tables</Filter>
<ClInclude Include="..\inc\cpuidflags.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="include\bdx86_table_xop.h">
<Filter>Header Files\private\x86\tables</Filter>
<ClInclude Include="include\nd_crt.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

@ -2,7 +2,7 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include "include/bddisasm_crt.h"
#include "include/nd_crt.h"
#include "../inc/bddisasm.h"
@ -18,32 +18,24 @@ static const char *gReg8Bit64[] =
{
"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b",
"r16b", "r17b", "r18b", "r19b", "r20b", "r21b", "r22b", "r23b",
"r24b", "r25b", "r26b", "r27b", "r28b", "r29b", "r30b", "r31b",
};
static const char *gReg16Bit[] =
{
"ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w",
"r16w", "r17w", "r18w", "r19w", "r20w", "r21w", "r22w", "r23w",
"r24w", "r25w", "r26w", "r27w", "r28w", "r29w", "r30w", "r31w",
};
static const char *gReg32Bit[] =
{
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
"r16d", "r17d", "r18d", "r19d", "r20d", "r21d", "r22d", "r23d",
"r24d", "r25d", "r26d", "r27d", "r28d", "r29d", "r30d", "r31d",
};
static const char *gReg64Bit[] =
{
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
};
static const char *gRegFpu[] =
@ -60,16 +52,12 @@ static const char *gRegControl[] =
{
"cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
"cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",
"cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
"cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
};
static const char *gRegDebug[] =
{
"dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7",
"dr8", "dr9", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15",
"dr16", "dr17", "dr18", "dr19", "dr20", "dr21", "dr22", "dr23",
"dr24", "dr25", "dr26", "dr27", "dr28", "dr29", "dr30", "dr31",
};
static const char *gRegTest[] =
@ -122,12 +110,21 @@ static const char *gRegTile[] =
"tmm0", "tmm1", "tmm2", "tmm3", "tmm4", "tmm5", "tmm6", "tmm7",
};
static const char *gConditionCodes[] =
{
"EQ", "LT", "LE", "UNORD", "NEQ", "NLT", "NLE", "ORD",
"EQ_UQ", "NGE", "NGT", "ND_FALSE", "NEQ_OQ", "GE", "GT", "TRUE",
"EQ_OS", "LT_OQ", "LE_OQ", "UNORD_S", "NEQ_US", "NLT_UQ", "NLE_UQ", "ORD_S",
"EQ_US", "NGE_UQ", "NGT_UQ", "FALSE_OS", "NEQ_OS", "GE_OQ", "GT_OQ", "TRUE_US",
};
static const char *gEmbeddedRounding[] =
{
"rn", "rd", "ru", "rz",
};
//
// NdSprintf
//
@ -220,61 +217,69 @@ NdToText(
nd_memzero(temp, sizeof(temp));
// First, store the prefixes.
// Check for REPZ/REPNZ support, and store prefixes.
if (Instrux->IsRepcEnabled)
if (Instrux->Rep != 0)
{
if (Instrux->Rep == ND_PREFIX_G1_REPE_REPZ)
// Check for REPZ/REPNZ support, and store prefixes.
if (ND_REPC_SUPPORT(Instrux))
{
res = nd_strcat_s(Buffer, BufferSize, "REPZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
if (Instrux->Rep == ND_PREFIX_G1_REPE_REPZ)
{
res = nd_strcat_s(Buffer, BufferSize, "REPZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else if (Instrux->Rep == ND_PREFIX_G1_REPNE_REPNZ)
{
res = nd_strcat_s(Buffer, BufferSize, "REPNZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
else if (Instrux->Rep == ND_PREFIX_G1_REPNE_REPNZ)
// Check for REP support and store prefixes.
if (ND_REP_SUPPORT(Instrux))
{
res = nd_strcat_s(Buffer, BufferSize, "REPNZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
if (Instrux->Rep == ND_PREFIX_G1_REPE_REPZ)
{
res = nd_strcat_s(Buffer, BufferSize, "REP ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else if (Instrux->Rep == ND_PREFIX_G1_REPNE_REPNZ)
{
res = nd_strcat_s(Buffer, BufferSize, "REPNZ ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
}
// Check for REP support and store prefixes.
if (Instrux->IsRepEnabled)
{
if (Instrux->Rep == ND_PREFIX_G1_REPE_REPZ)
if (Instrux->IsXreleaseEnabled)
{
res = nd_strcat_s(Buffer, BufferSize, "REP ");
res = nd_strcat_s(Buffer, BufferSize, "XRELEASE ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else if (Instrux->Rep == ND_PREFIX_G1_REPNE_REPNZ)
else if (Instrux->IsXacquireEnabled)
{
res = nd_strcat_s(Buffer, BufferSize, "REPNZ ");
res = nd_strcat_s(Buffer, BufferSize, "XACQUIRE ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
if (Instrux->IsXreleaseEnabled)
{
res = nd_strcat_s(Buffer, BufferSize, "XRELEASE ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else if (Instrux->IsXacquireEnabled)
{
res = nd_strcat_s(Buffer, BufferSize, "XACQUIRE ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
if (Instrux->IsLockEnabled)
if (Instrux->HasLock)
{
res = nd_strcat_s(Buffer, BufferSize, "LOCK ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
if (ND_LOCK_SUPPORT(Instrux))
{
res = nd_strcat_s(Buffer, BufferSize, "LOCK ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
if (Instrux->IsBndEnabled)
if (Instrux->Rep == ND_PREFIX_G1_BND)
{
res = nd_strcat_s(Buffer, BufferSize, "BND ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
if (ND_BND_SUPPORT(Instrux))
{
res = nd_strcat_s(Buffer, BufferSize, "BND ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
if (Instrux->IsBhintEnabled)
if (Instrux->HasSeg && ND_BHINT_SUPPORT(Instrux))
{
switch (Instrux->Seg)
{
@ -298,27 +303,23 @@ NdToText(
}
}
if (Instrux->IsDntEnabled)
if (Instrux->HasSeg && ND_DNT_SUPPORT(Instrux))
{
res = nd_strcat_s(Buffer, BufferSize, "DNT ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
if (!Instrux->IsCetTracked)
{
res = nd_strcat_s(Buffer, BufferSize, "DNT ");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
// Store the mnemonic.
res = nd_strcat_s(Buffer, BufferSize, Instrux->Mnemonic);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
// Store NF specifier, if NoFlags presetn.
if (Instrux->HasNf)
// Store condition code, if any.
if (ND_HAS_SSE_CONDITION(Instrux))
{
res = nd_strcat_s(Buffer, BufferSize, "{NF}");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Store ZU specifier, if ZeroUpper present.
if (Instrux->HasZu)
{
res = nd_strcat_s(Buffer, BufferSize, "{ZU}");
res = nd_strcat_s(Buffer, BufferSize, gConditionCodes[Instrux->SseCondition]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
@ -405,7 +406,7 @@ NdToText(
{
case ND_SIZE_8BIT:
// 8 bit register.
if ((Instrux->EncMode != ND_ENCM_LEGACY) || Instrux->HasRex || Instrux->HasRex2)
if ((Instrux->EncMode != ND_ENCM_LEGACY) || Instrux->HasRex)
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit64[pOp->Info.Register.Reg]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
@ -443,6 +444,11 @@ NdToText(
case ND_REG_SEG:
{
if (pOp->Info.Register.Reg >= ND_MAX_SEG_REGS)
{
return ND_STATUS_INVALID_INSTRUX;
}
res = nd_strcat_s(Buffer, BufferSize, gRegSeg[pOp->Info.Register.Reg]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
@ -665,7 +671,7 @@ NdToText(
}
break;
case ND_OP_ADDR_FAR:
case ND_OP_ADDR:
{
switch (Instrux->AddrLength)
{
@ -695,36 +701,6 @@ NdToText(
}
break;
case ND_OP_ADDR_NEAR:
{
status = NdSprintf(temp, sizeof(temp), "0x%016llx", pOp->Info.AddressNear.Target);
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
break;
case ND_OP_DFV:
{
status = NdSprintf(temp, sizeof(temp), "%c%c%c%c",
pOp->Info.DefaultFlags.OF ? '1' : '0',
pOp->Info.DefaultFlags.SF ? '1' : '0',
pOp->Info.DefaultFlags.ZF ? '1' : '0',
pOp->Info.DefaultFlags.CF ? '1' : '0');
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
break;
case ND_OP_MEM:
{
// Prepend the size. For VSIB addressing, store the VSIB element size, not the total accessed size.
@ -779,6 +755,11 @@ NdToText(
// Perpend the segment, only if it is overridden via a prefix.
if (pOp->Info.Memory.HasSeg && Instrux->HasSeg)
{
if (pOp->Info.Memory.Seg >= ND_MAX_SEG_REGS)
{
return ND_STATUS_INVALID_INSTRUX;
}
if ((ND_CODE_64 != Instrux->DefCode) || (NDR_FS == pOp->Info.Memory.Seg) ||
(NDR_GS == pOp->Info.Memory.Seg))
{
@ -797,20 +778,16 @@ NdToText(
// Base, if any.
if (pOp->Info.Memory.HasBase)
{
if (pOp->Info.Memory.Base >= ND_MAX_GPR_REGS)
{
return ND_STATUS_INVALID_INSTRUX;
}
switch (pOp->Info.Memory.BaseSize)
{
case ND_SIZE_8BIT:
if ((Instrux->EncMode != ND_ENCM_LEGACY) || Instrux->HasRex || Instrux->HasRex2)
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit64[pOp->Info.Memory.Base]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit[pOp->Info.Memory.Base]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit[pOp->Info.Memory.Base]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
break;
case ND_SIZE_16BIT:
res = nd_strcat_s(Buffer, BufferSize, gReg16Bit[pOp->Info.Memory.Base]);
@ -846,16 +823,8 @@ NdToText(
switch (pOp->Info.Memory.IndexSize)
{
case ND_SIZE_8BIT:
if ((Instrux->EncMode != ND_ENCM_LEGACY) || Instrux->HasRex || Instrux->HasRex2)
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit64[pOp->Info.Memory.Index]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
else
{
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit[pOp->Info.Memory.Index]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
res = nd_strcat_s(Buffer, BufferSize, gReg8Bit[pOp->Info.Memory.Index]);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
break;
case ND_SIZE_16BIT:
res = nd_strcat_s(Buffer, BufferSize, gReg16Bit[pOp->Info.Memory.Index]);
@ -944,18 +913,7 @@ NdToText(
// Now displacement.
if (pOp->Info.Memory.HasBase || pOp->Info.Memory.HasIndex)
{
ND_BOOL sign;
if (ND_GET_SIGN(8, pOp->Info.Memory.Disp))
{
sign = ND_TRUE;
}
else
{
sign = ND_FALSE;
}
res = nd_strcat_s(Buffer, BufferSize, sign ? "-" : "+");
res = nd_strcat_s(Buffer, BufferSize, Instrux->SignDisp ? "-" : "+");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
@ -993,19 +951,6 @@ NdToText(
// And the ending "]"
res = nd_strcat_s(Buffer, BufferSize, "]");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
// Handle memory broadcast.
if (pOp->Info.Memory.HasBroadcast)
{
status = NdSprintf(temp, sizeof(temp), "{1to%d}", pOp->Info.Memory.Broadcast.Count);
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}
break;
@ -1013,10 +958,28 @@ NdToText(
return ND_STATUS_INVALID_INSTRUX;
}
// Handle memory broadcast.
if (pOp->Decorator.HasBroadcast)
{
status = NdSprintf(temp, sizeof(temp), "{1to%d}", pOp->Decorator.Broadcast.Count);
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Handle masking.
if (pOp->Decorator.HasMask)
{
status = NdSprintf(temp, sizeof(temp), "{%s}", gRegMask[pOp->Decorator.Msk]);
if (pOp->Decorator.Mask.Msk >= ND_MAX_MSK_REGS)
{
return ND_STATUS_INVALID_INSTRUX;
}
status = NdSprintf(temp, sizeof(temp), "{%s}", gRegMask[pOp->Decorator.Mask.Msk]);
if (!ND_SUCCESS(status))
{
return status;
@ -1033,30 +996,30 @@ NdToText(
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// If this is the last reg/mem operand, display {sae} and {er} decorators.
if ((pOp->Type == ND_OP_MEM || pOp->Type == ND_OP_REG) &&
(opIndex + 1 >= Instrux->ExpOperandsCount || Instrux->Operands[opIndex + 1].Type == ND_OP_IMM))
// Append Suppress All Exceptions decorator.
if (pOp->Decorator.HasSae && !pOp->Decorator.HasEr)
{
// Append Suppress All Exceptions decorator.
if (Instrux->HasSae && !Instrux->HasEr)
// ER implies SAE, so if we have ER, we will list that.
res = nd_strcat_s(Buffer, BufferSize, ", {sae}");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
// Append Embedded Rounding decorator.
if (pOp->Decorator.HasEr)
{
if (Instrux->RoundingMode >= 4)
{
// ER implies SAE, so if we have ER, we will list that.
res = nd_strcat_s(Buffer, BufferSize, ", {sae}");
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
return ND_STATUS_INVALID_INSTRUX;
}
// Append Embedded Rounding decorator.
if (Instrux->HasEr)
status = NdSprintf(temp, sizeof(temp), ", {%s-sae}", gEmbeddedRounding[Instrux->RoundingMode]);
if (!ND_SUCCESS(status))
{
status = NdSprintf(temp, sizeof(temp), ", {%s-sae}", gEmbeddedRounding[Instrux->RoundingMode]);
if (!ND_SUCCESS(status))
{
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
return status;
}
res = nd_strcat_s(Buffer, BufferSize, temp);
RET_EQ(res, ND_NULL, ND_STATUS_BUFFER_OVERFLOW);
}
}

@ -2,7 +2,7 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include "include/bddisasm_crt.h"
#include "include/nd_crt.h"
#include "../inc/bddisasm.h"

@ -2,7 +2,7 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include "include/bddisasm_crt.h"
#include "include/nd_crt.h"
//
// nd_strcat_s

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 Bitdefender
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
@ -7,46 +7,39 @@
// This file was auto-generated by generate_tables.py. DO NOT MODIFY!
//
#ifndef BDX86_MNEMONICS_H
#define BDX86_MNEMONICS_H
#ifndef MNEMONICS_H
#define MNEMONICS_H
const char *gMnemonics[1786] =
const char *gMnemonics[1751] =
{
"AAA", "AAD", "AADD", "AAM", "AAND", "AAS", "ADC", "ADCX", "ADD",
"ADDPD", "ADDPS", "ADDSD", "ADDSS", "ADDSUBPD", "ADDSUBPS", "ADOX",
"AESDEC", "AESDEC128KL", "AESDEC256KL", "AESDECLAST", "AESDECWIDE128KL",
"AESDECWIDE256KL", "AESENC", "AESENC128KL", "AESENC256KL", "AESENCLAST",
"AESENCWIDE128KL", "AESENCWIDE256KL", "AESIMC", "AESKEYGENASSIST",
"AND", "ANDN", "ANDNPD", "ANDNPS", "ANDPD", "ANDPS", "AOR", "ARPL",
"AXOR", "BEXTR", "BLCFILL", "BLCI", "BLCIC", "BLCMSK", "BLCS",
"BLENDPD", "BLENDPS", "BLENDVPD", "BLENDVPS", "BLSFILL", "BLSI",
"BLSIC", "BLSMSK", "BLSR", "BNDCL", "BNDCN", "BNDCU", "BNDLDX",
"BNDMK", "BNDMOV", "BNDSTX", "BOUND", "BSF", "BSR", "BSWAP",
"BT", "BTC", "BTR", "BTS", "BZHI", "CALL", "CALLF", "CBW", "CCMPBE",
"CCMPC", "CCMPF", "CCMPL", "CCMPLE", "CCMPNBE", "CCMPNC", "CCMPNL",
"CCMPNLE", "CCMPNO", "CCMPNS", "CCMPNZ", "CCMPO", "CCMPS", "CCMPT",
"CCMPZ", "CDQ", "CDQE", "CFCMOVBE", "CFCMOVC", "CFCMOVL", "CFCMOVLE",
"CFCMOVNBE", "CFCMOVNC", "CFCMOVNL", "CFCMOVNLE", "CFCMOVNO",
"CFCMOVNP", "CFCMOVNS", "CFCMOVNZ", "CFCMOVO", "CFCMOVP", "CFCMOVS",
"CFCMOVZ", "CLAC", "CLC", "CLD", "CLDEMOTE", "CLEVICT0", "CLEVICT1",
"CLFLUSH", "CLFLUSHOPT", "CLGI", "CLI", "CLRSSBSY", "CLTS", "CLUI",
"CLWB", "CLZERO", "CMC", "CMOVBE", "CMOVC", "CMOVL", "CMOVLE",
"CMOVNBE", "CMOVNC", "CMOVNL", "CMOVNLE", "CMOVNO", "CMOVNP",
"CMOVNS", "CMOVNZ", "CMOVO", "CMOVP", "CMOVS", "CMOVZ", "CMP",
"CMPBEXADD", "CMPCXADD", "CMPLEXADD", "CMPLXADD", "CMPNBEXADD",
"ALTINST", "AND", "ANDN", "ANDNPD", "ANDNPS", "ANDPD", "ANDPS",
"AOR", "ARPL", "AXOR", "BEXTR", "BLCFILL", "BLCI", "BLCIC", "BLCMSK",
"BLCS", "BLENDPD", "BLENDPS", "BLENDVPD", "BLENDVPS", "BLSFILL",
"BLSI", "BLSIC", "BLSMSK", "BLSR", "BNDCL", "BNDCN", "BNDCU",
"BNDLDX", "BNDMK", "BNDMOV", "BNDSTX", "BOUND", "BSF", "BSR",
"BSWAP", "BT", "BTC", "BTR", "BTS", "BZHI", "CALL", "CALLF",
"CBW", "CDQ", "CDQE", "CLAC", "CLC", "CLD", "CLDEMOTE", "CLEVICT0",
"CLEVICT1", "CLFLUSH", "CLFLUSHOPT", "CLGI", "CLI", "CLRSSBSY",
"CLTS", "CLUI", "CLWB", "CLZERO", "CMC", "CMOVBE", "CMOVC", "CMOVL",
"CMOVLE", "CMOVNBE", "CMOVNC", "CMOVNL", "CMOVNLE", "CMOVNO",
"CMOVNP", "CMOVNS", "CMOVNZ", "CMOVO", "CMOVP", "CMOVS", "CMOVZ",
"CMP", "CMPBEXADD", "CMPCXADD", "CMPLEXADD", "CMPLXADD", "CMPNBEXADD",
"CMPNCXADD", "CMPNLEXADD", "CMPNLXADD", "CMPNOXADD", "CMPNPXADD",
"CMPNSXADD", "CMPNZXADD", "CMPOXADD", "CMPPD", "CMPPS", "CMPPXADD",
"CMPSB", "CMPSD", "CMPSQ", "CMPSS", "CMPSW", "CMPSXADD", "CMPXCHG",
"CMPXCHG16B", "CMPXCHG8B", "CMPZXADD", "COMISD", "COMISS", "CPUID",
"CQO", "CRC32", "CTESTBE", "CTESTC", "CTESTF", "CTESTL", "CTESTLE",
"CTESTNBE", "CTESTNC", "CTESTNL", "CTESTNLE", "CTESTNO", "CTESTNS",
"CTESTNZ", "CTESTO", "CTESTS", "CTESTT", "CTESTZ", "CVTDQ2PD",
"CVTDQ2PS", "CVTPD2DQ", "CVTPD2PI", "CVTPD2PS", "CVTPI2PD", "CVTPI2PS",
"CVTPS2DQ", "CVTPS2PD", "CVTPS2PI", "CVTSD2SI", "CVTSD2SS", "CVTSI2SD",
"CVTSI2SS", "CVTSS2SD", "CVTSS2SI", "CVTTPD2DQ", "CVTTPD2PI",
"CVTTPS2DQ", "CVTTPS2PI", "CVTTSD2SI", "CVTTSS2SI", "CWD", "CWDE",
"DAA", "DAS", "DEC", "DELAY", "DIV", "DIVPD", "DIVPS", "DIVSD",
"DIVSS", "DPPD", "DPPS", "EMMS", "ENCLS", "ENCLU", "ENCLV", "ENCODEKEY128",
"CPU_READ", "CPU_WRITE", "CQO", "CRC32", "CVTDQ2PD", "CVTDQ2PS",
"CVTPD2DQ", "CVTPD2PI", "CVTPD2PS", "CVTPI2PD", "CVTPI2PS", "CVTPS2DQ",
"CVTPS2PD", "CVTPS2PI", "CVTSD2SI", "CVTSD2SS", "CVTSI2SD", "CVTSI2SS",
"CVTSS2SD", "CVTSS2SI", "CVTTPD2DQ", "CVTTPD2PI", "CVTTPS2DQ",
"CVTTPS2PI", "CVTTSD2SI", "CVTTSS2SI", "CWD", "CWDE", "DAA",
"DAS", "DEC", "DELAY", "DIV", "DIVPD", "DIVPS", "DIVSD", "DIVSS",
"DMINT", "DPPD", "DPPS", "EMMS", "ENCLS", "ENCLU", "ENCLV", "ENCODEKEY128",
"ENCODEKEY256", "ENDBR32", "ENDBR64", "ENQCMD", "ENQCMDS", "ENTER",
"ERETS", "ERETU", "EXTRACTPS", "EXTRQ", "F2XM1", "FABS", "FADD",
"FADDP", "FBLD", "FBSTP", "FCHS", "FCMOVB", "FCMOVBE", "FCMOVE",
@ -68,24 +61,24 @@ const char *gMnemonics[1786] =
"INCSSPD", "INCSSPQ", "INSB", "INSD", "INSERTPS", "INSERTQ",
"INSW", "INT", "INT1", "INT3", "INTO", "INVD", "INVEPT", "INVLPG",
"INVLPGA", "INVLPGB", "INVPCID", "INVVPID", "IRETD", "IRETQ",
"IRETW", "JBE", "JC", "JCXZ", "JECXZ", "JL", "JLE", "JMP", "JMPABS",
"JMPE", "JMPF", "JNBE", "JNC", "JNL", "JNLE", "JNO", "JNP", "JNS",
"JNZ", "JO", "JP", "JRCXZ", "JS", "JZ", "KADDB", "KADDD", "KADDQ",
"KADDW", "KANDB", "KANDD", "KANDNB", "KANDND", "KANDNQ", "KANDNW",
"KANDQ", "KANDW", "KMERGE2L1H", "KMERGE2L1L", "KMOVB", "KMOVD",
"KMOVQ", "KMOVW", "KNOTB", "KNOTD", "KNOTQ", "KNOTW", "KORB",
"KORD", "KORQ", "KORTESTB", "KORTESTD", "KORTESTQ", "KORTESTW",
"KORW", "KSHIFTLB", "KSHIFTLD", "KSHIFTLQ", "KSHIFTLW", "KSHIFTRB",
"KSHIFTRD", "KSHIFTRQ", "KSHIFTRW", "KTESTB", "KTESTD", "KTESTQ",
"KTESTW", "KUNPCKBW", "KUNPCKDQ", "KUNPCKWD", "KXNORB", "KXNORD",
"KXNORQ", "KXNORW", "KXORB", "KXORD", "KXORQ", "KXORW", "LAHF",
"LAR", "LDDQU", "LDMXCSR", "LDS", "LDTILECFG", "LEA", "LEAVE",
"LES", "LFENCE", "LFS", "LGDT", "LGS", "LIDT", "LKGS", "LLDT",
"LLWPCB", "LMSW", "LOADIWKEY", "LODSB", "LODSD", "LODSQ", "LODSW",
"LOOP", "LOOPNZ", "LOOPZ", "LSL", "LSS", "LTR", "LWPINS", "LWPVAL",
"LZCNT", "MASKMOVDQU", "MASKMOVQ", "MAXPD", "MAXPS", "MAXSD",
"MAXSS", "MCOMMIT", "MFENCE", "MINPD", "MINPS", "MINSD", "MINSS",
"MONITOR", "MONITORX", "MOV", "MOVAPD", "MOVAPS", "MOVBE", "MOVD",
"IRETW", "JBE", "JC", "JCXZ", "JECXZ", "JL", "JLE", "JMP", "JMPE",
"JMPF", "JNBE", "JNC", "JNL", "JNLE", "JNO", "JNP", "JNS", "JNZ",
"JO", "JP", "JRCXZ", "JS", "JZ", "KADDB", "KADDD", "KADDQ", "KADDW",
"KANDB", "KANDD", "KANDNB", "KANDND", "KANDNQ", "KANDNW", "KANDQ",
"KANDW", "KMERGE2L1H", "KMERGE2L1L", "KMOVB", "KMOVD", "KMOVQ",
"KMOVW", "KNOTB", "KNOTD", "KNOTQ", "KNOTW", "KORB", "KORD",
"KORQ", "KORTESTB", "KORTESTD", "KORTESTQ", "KORTESTW", "KORW",
"KSHIFTLB", "KSHIFTLD", "KSHIFTLQ", "KSHIFTLW", "KSHIFTRB", "KSHIFTRD",
"KSHIFTRQ", "KSHIFTRW", "KTESTB", "KTESTD", "KTESTQ", "KTESTW",
"KUNPCKBW", "KUNPCKDQ", "KUNPCKWD", "KXNORB", "KXNORD", "KXNORQ",
"KXNORW", "KXORB", "KXORD", "KXORQ", "KXORW", "LAHF", "LAR",
"LDDQU", "LDMXCSR", "LDS", "LDTILECFG", "LEA", "LEAVE", "LES",
"LFENCE", "LFS", "LGDT", "LGS", "LIDT", "LKGS", "LLDT", "LLWPCB",
"LMSW", "LOADIWKEY", "LODSB", "LODSD", "LODSQ", "LODSW", "LOOP",
"LOOPNZ", "LOOPZ", "LSL", "LSS", "LTR", "LWPINS", "LWPVAL", "LZCNT",
"MASKMOVDQU", "MASKMOVQ", "MAXPD", "MAXPS", "MAXSD", "MAXSS",
"MCOMMIT", "MFENCE", "MINPD", "MINPS", "MINSD", "MINSS", "MONITOR",
"MONITORX", "MONTMUL", "MOV", "MOVAPD", "MOVAPS", "MOVBE", "MOVD",
"MOVDDUP", "MOVDIR64B", "MOVDIRI", "MOVDQ2Q", "MOVDQA", "MOVDQU",
"MOVHLPS", "MOVHPD", "MOVHPS", "MOVLHPS", "MOVLPD", "MOVLPS",
"MOVMSKPD", "MOVMSKPS", "MOVNTDQ", "MOVNTDQA", "MOVNTI", "MOVNTPD",
@ -111,52 +104,52 @@ const char *gMnemonics[1786] =
"PMINUD", "PMINUW", "PMOVMSKB", "PMOVSXBD", "PMOVSXBQ", "PMOVSXBW",
"PMOVSXDQ", "PMOVSXWD", "PMOVSXWQ", "PMOVZXBD", "PMOVZXBQ", "PMOVZXBW",
"PMOVZXDQ", "PMOVZXWD", "PMOVZXWQ", "PMULDQ", "PMULHRSW", "PMULHRW",
"PMULHUW", "PMULHW", "PMULLD", "PMULLW", "PMULUDQ", "POP", "POP2",
"POP2P", "POPA", "POPAD", "POPCNT", "POPFD", "POPFQ", "POPFW",
"POPP", "POR", "PREFETCH", "PREFETCHE", "PREFETCHIT0", "PREFETCHIT1",
"PREFETCHM", "PREFETCHNTA", "PREFETCHT0", "PREFETCHT1", "PREFETCHT2",
"PREFETCHW", "PREFETCHWT1", "PSADBW", "PSHUFB", "PSHUFD", "PSHUFHW",
"PSHUFLW", "PSHUFW", "PSIGNB", "PSIGND", "PSIGNW", "PSLLD", "PSLLDQ",
"PSLLQ", "PSLLW", "PSMASH", "PSRAD", "PSRAW", "PSRLD", "PSRLDQ",
"PSRLQ", "PSRLW", "PSUBB", "PSUBD", "PSUBQ", "PSUBSB", "PSUBSW",
"PSUBUSB", "PSUBUSW", "PSUBW", "PSWAPD", "PTEST", "PTWRITE",
"PUNPCKHBW", "PUNPCKHDQ", "PUNPCKHQDQ", "PUNPCKHWD", "PUNPCKLBW",
"PUNPCKLDQ", "PUNPCKLQDQ", "PUNPCKLWD", "PUSH", "PUSH2", "PUSH2P",
"PUSHA", "PUSHAD", "PUSHFD", "PUSHFQ", "PUSHFW", "PUSHP", "PVALIDATE",
"PXOR", "RCL", "RCPPS", "RCPSS", "RCR", "RDFSBASE", "RDGSBASE",
"RDMSR", "RDMSRLIST", "RDPID", "RDPKRU", "RDPMC", "RDPRU", "RDRAND",
"RDSEED", "RDSSPD", "RDSSPQ", "RDTSC", "RDTSCP", "RETF", "RETN",
"RMPADJUST", "RMPQUERY", "RMPUPDATE", "ROL", "ROR", "RORX", "ROUNDPD",
"ROUNDPS", "ROUNDSD", "ROUNDSS", "RSM", "RSQRTPS", "RSQRTSS",
"RSTORSSP", "SAHF", "SAL", "SALC", "SAR", "SARX", "SAVEPREVSSP",
"SBB", "SCASB", "SCASD", "SCASQ", "SCASW", "SEAMCALL", "SEAMOPS",
"SEAMRET", "SENDUIPI", "SERIALIZE", "SETBE", "SETC", "SETL",
"SETLE", "SETNBE", "SETNC", "SETNL", "SETNLE", "SETNO", "SETNP",
"SETNS", "SETNZ", "SETO", "SETP", "SETS", "SETSSBSY", "SETZ",
"SFENCE", "SGDT", "SHA1MSG1", "SHA1MSG2", "SHA1NEXTE", "SHA1RNDS4",
"SHA256MSG1", "SHA256MSG2", "SHA256RNDS2", "SHL", "SHLD", "SHLX",
"SHR", "SHRD", "SHRX", "SHUFPD", "SHUFPS", "SIDT", "SKINIT",
"SLDT", "SLWPCB", "SMSW", "SPFLT", "SQRTPD", "SQRTPS", "SQRTSD",
"SQRTSS", "STAC", "STC", "STD", "STGI", "STI", "STMXCSR", "STOSB",
"STOSD", "STOSQ", "STOSW", "STR", "STTILECFG", "STUI", "SUB",
"SUBPD", "SUBPS", "SUBSD", "SUBSS", "SWAPGS", "SYSCALL", "SYSENTER",
"SYSEXIT", "SYSRET", "T1MSKC", "TCMMIMFP16PS", "TCMMRLFP16PS",
"TDCALL", "TDPBF16PS", "TDPBSSD", "TDPBSUD", "TDPBUSD", "TDPBUUD",
"TDPFP16PS", "TEST", "TESTUI", "TILELOADD", "TILELOADDT1", "TILERELEASE",
"TILESTORED", "TILEZERO", "TLBSYNC", "TPAUSE", "TZCNT", "TZMSK",
"UCOMISD", "UCOMISS", "UD0", "UD1", "UD2", "UIRET", "UMONITOR",
"UMWAIT", "UNPCKHPD", "UNPCKHPS", "UNPCKLPD", "UNPCKLPS", "URDMSR",
"UWRMSR", "V4FMADDPS", "V4FMADDSS", "V4FNMADDPS", "V4FNMADDSS",
"VADDPD", "VADDPH", "VADDPS", "VADDSD", "VADDSH", "VADDSS", "VADDSUBPD",
"VADDSUBPS", "VAESDEC", "VAESDECLAST", "VAESENC", "VAESENCLAST",
"VAESIMC", "VAESKEYGENASSIST", "VALIGND", "VALIGNQ", "VANDNPD",
"VANDNPS", "VANDPD", "VANDPS", "VBCSTNEBF162PS", "VBCSTNESH2PS",
"VBLENDMPD", "VBLENDMPS", "VBLENDPD", "VBLENDPS", "VBLENDVPD",
"VBLENDVPS", "VBROADCASTF128", "VBROADCASTF32X2", "VBROADCASTF32X4",
"VBROADCASTF32X8", "VBROADCASTF64X2", "VBROADCASTF64X4", "VBROADCASTI128",
"VBROADCASTI32X2", "VBROADCASTI32X4", "VBROADCASTI32X8", "VBROADCASTI64X2",
"VBROADCASTI64X4", "VBROADCASTSD", "VBROADCASTSS", "VCMPPD",
"VCMPPH", "VCMPPS", "VCMPSD", "VCMPSH", "VCMPSS", "VCOMISD",
"PMULHUW", "PMULHW", "PMULLD", "PMULLW", "PMULUDQ", "POP", "POPA",
"POPAD", "POPCNT", "POPFD", "POPFQ", "POPFW", "POR", "PREFETCH",
"PREFETCHE", "PREFETCHIT0", "PREFETCHIT1", "PREFETCHM", "PREFETCHNTA",
"PREFETCHT0", "PREFETCHT1", "PREFETCHT2", "PREFETCHW", "PREFETCHWT1",
"PSADBW", "PSHUFB", "PSHUFD", "PSHUFHW", "PSHUFLW", "PSHUFW",
"PSIGNB", "PSIGND", "PSIGNW", "PSLLD", "PSLLDQ", "PSLLQ", "PSLLW",
"PSMASH", "PSRAD", "PSRAW", "PSRLD", "PSRLDQ", "PSRLQ", "PSRLW",
"PSUBB", "PSUBD", "PSUBQ", "PSUBSB", "PSUBSW", "PSUBUSB", "PSUBUSW",
"PSUBW", "PSWAPD", "PTEST", "PTWRITE", "PUNPCKHBW", "PUNPCKHDQ",
"PUNPCKHQDQ", "PUNPCKHWD", "PUNPCKLBW", "PUNPCKLDQ", "PUNPCKLQDQ",
"PUNPCKLWD", "PUSH", "PUSHA", "PUSHAD", "PUSHFD", "PUSHFQ", "PUSHFW",
"PVALIDATE", "PXOR", "RCL", "RCPPS", "RCPSS", "RCR", "RDFSBASE",
"RDGSBASE", "RDMSR", "RDMSRLIST", "RDPID", "RDPKRU", "RDPMC",
"RDPRU", "RDRAND", "RDSEED", "RDSHR", "RDSSPD", "RDSSPQ", "RDTSC",
"RDTSCP", "RETF", "RETN", "RMPADJUST", "RMPQUERY", "RMPUPDATE",
"ROL", "ROR", "RORX", "ROUNDPD", "ROUNDPS", "ROUNDSD", "ROUNDSS",
"RSDC", "RSLDT", "RSM", "RSQRTPS", "RSQRTSS", "RSTORSSP", "RSTS",
"SAHF", "SAL", "SALC", "SAR", "SARX", "SAVEPREVSSP", "SBB", "SCASB",
"SCASD", "SCASQ", "SCASW", "SEAMCALL", "SEAMOPS", "SEAMRET",
"SENDUIPI", "SERIALIZE", "SETBE", "SETC", "SETL", "SETLE", "SETNBE",
"SETNC", "SETNL", "SETNLE", "SETNO", "SETNP", "SETNS", "SETNZ",
"SETO", "SETP", "SETS", "SETSSBSY", "SETZ", "SFENCE", "SGDT",
"SHA1MSG1", "SHA1MSG2", "SHA1NEXTE", "SHA1RNDS4", "SHA256MSG1",
"SHA256MSG2", "SHA256RNDS2", "SHL", "SHLD", "SHLX", "SHR", "SHRD",
"SHRX", "SHUFPD", "SHUFPS", "SIDT", "SKINIT", "SLDT", "SLWPCB",
"SMINT", "SMSW", "SPFLT", "SQRTPD", "SQRTPS", "SQRTSD", "SQRTSS",
"STAC", "STC", "STD", "STGI", "STI", "STMXCSR", "STOSB", "STOSD",
"STOSQ", "STOSW", "STR", "STTILECFG", "STUI", "SUB", "SUBPD",
"SUBPS", "SUBSD", "SUBSS", "SVDC", "SVLDT", "SVTS", "SWAPGS",
"SYSCALL", "SYSENTER", "SYSEXIT", "SYSRET", "T1MSKC", "TCMMIMFP16PS",
"TCMMRLFP16PS", "TDCALL", "TDPBF16PS", "TDPBSSD", "TDPBSUD",
"TDPBUSD", "TDPBUUD", "TDPFP16PS", "TEST", "TESTUI", "TILELOADD",
"TILELOADDT1", "TILERELEASE", "TILESTORED", "TILEZERO", "TLBSYNC",
"TPAUSE", "TZCNT", "TZMSK", "UCOMISD", "UCOMISS", "UD0", "UD1",
"UD2", "UIRET", "UMONITOR", "UMWAIT", "UNPCKHPD", "UNPCKHPS",
"UNPCKLPD", "UNPCKLPS", "V4FMADDPS", "V4FMADDSS", "V4FNMADDPS",
"V4FNMADDSS", "VADDPD", "VADDPH", "VADDPS", "VADDSD", "VADDSH",
"VADDSS", "VADDSUBPD", "VADDSUBPS", "VAESDEC", "VAESDECLAST",
"VAESENC", "VAESENCLAST", "VAESIMC", "VAESKEYGENASSIST", "VALIGND",
"VALIGNQ", "VANDNPD", "VANDNPS", "VANDPD", "VANDPS", "VBCSTNEBF162PS",
"VBCSTNESH2PS", "VBLENDMPD", "VBLENDMPS", "VBLENDPD", "VBLENDPS",
"VBLENDVPD", "VBLENDVPS", "VBROADCASTF128", "VBROADCASTF32X2",
"VBROADCASTF32X4", "VBROADCASTF32X8", "VBROADCASTF64X2", "VBROADCASTF64X4",
"VBROADCASTI128", "VBROADCASTI32X2", "VBROADCASTI32X4", "VBROADCASTI32X8",
"VBROADCASTI64X2", "VBROADCASTI64X4", "VBROADCASTSD", "VBROADCASTSS",
"VCMPPD", "VCMPPH", "VCMPPS", "VCMPSD", "VCMPSH", "VCMPSS", "VCOMISD",
"VCOMISH", "VCOMISS", "VCOMPRESSPD", "VCOMPRESSPS", "VCVTDQ2PD",
"VCVTDQ2PH", "VCVTDQ2PS", "VCVTNE2PS2BF16", "VCVTNEEBF162PS",
"VCVTNEEPH2PS", "VCVTNEOBF162PS", "VCVTNEOPH2PS", "VCVTNEPS2BF16",
@ -313,11 +306,13 @@ const char *gMnemonics[1786] =
"VUCOMISH", "VUCOMISS", "VUNPCKHPD", "VUNPCKHPS", "VUNPCKLPD",
"VUNPCKLPS", "VXORPD", "VXORPS", "VZEROALL", "VZEROUPPER", "WAIT",
"WBINVD", "WBNOINVD", "WRFSBASE", "WRGSBASE", "WRMSR", "WRMSRLIST",
"WRMSRNS", "WRPKRU", "WRSSD", "WRSSQ", "WRUSSD", "WRUSSQ", "XABORT",
"XADD", "XBEGIN", "XCHG", "XEND", "XGETBV", "XLATB", "XOR", "XORPD",
"XORPS", "XRESLDTRK", "XRSTOR", "XRSTOR64", "XRSTORS", "XRSTORS64",
"XSAVE", "XSAVE64", "XSAVEC", "XSAVEC64", "XSAVEOPT", "XSAVEOPT64",
"XSAVES", "XSAVES64", "XSETBV", "XSUSLDTRK", "XTEST",
"WRMSRNS", "WRPKRU", "WRSHR", "WRSSD", "WRSSQ", "WRUSSD", "WRUSSQ",
"XABORT", "XADD", "XBEGIN", "XCHG", "XCRYPTCBC", "XCRYPTCFB",
"XCRYPTCTR", "XCRYPTECB", "XCRYPTOFB", "XEND", "XGETBV", "XLATB",
"XOR", "XORPD", "XORPS", "XRESLDTRK", "XRSTOR", "XRSTOR64", "XRSTORS",
"XRSTORS64", "XSAVE", "XSAVE64", "XSAVEC", "XSAVEC64", "XSAVEOPT",
"XSAVEOPT64", "XSAVES", "XSAVES64", "XSETBV", "XSHA1", "XSHA256",
"XSTORE", "XSUSLDTRK", "XTEST",
};

@ -5,7 +5,7 @@
#ifndef ND_CRT_H
#define ND_CRT_H
#include "../../inc/bddisasm_types.h"
#include "../../inc/disasmtypes.h"
#ifndef UNREFERENCED_PARAMETER
#define UNREFERENCED_PARAMETER(P) ((void)(P))

@ -2,8 +2,8 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BDX86_PREFIXES_H
#define BDX86_PREFIXES_H
#ifndef PREFIXES_H
#define PREFIXES_H
#define ND_PREF_CODE_NONE 0
#define ND_PREF_CODE_STANDARD 1
@ -26,9 +26,9 @@ static const ND_UINT8 gPrefixesMap[256] =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
};
#endif // BDX86_PREFIXES_H
#endif // PREFIXES_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -2,10 +2,10 @@
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BDX86_TABLEDEFS_H
#define BDX86_TABLEDEFS_H
#ifndef TABLEDEFS_H
#define TABLEDEFS_H
#include "../inc/bddisasm_types.h"
#include "../inc/disasmtypes.h"
//
// Types of tables.
@ -14,29 +14,27 @@ typedef enum _ND_ILUT_TYPE
{
ND_ILUT_INSTRUCTION = 0,// Table contains one entry that directly points to an instruction.
ND_ILUT_OPCODE, // Table contains 256 entries. Next entry is selected using an opcode.
ND_ILUT_OPCODE_LAST, // Table contains 256 entries. Next entry is selected using an opcode, but the
// opcode follows the instruction as the last byte.
ND_ILUT_MODRM_REG, // Table contains 8 entries. Next entry is selected using modrm.reg.
ND_ILUT_OPCODE_3DNOW, // Table contains 256 entries. Next entry is selected using an opcode, but the
// opcode follows the instruction.
ND_ILUT_MODRM_MOD, // Table contains 2 entries. Next entry is selected using modrm.mod (0 - mem, 1 - reg)
ND_ILUT_MODRM_REG, // Table contains 8 entries. Next entry is selected using modrm.reg.
ND_ILUT_MODRM_RM, // Table contains 8 entries. Next entry is selected using modrm.rm.
ND_ILUT_MAN_PREFIX, // Table contains 4 entries. Next entry is 0 (no prefix), 1 (0x66), 2 (0xF3), 3 (0xF2).
ND_ILUT_MODE, // Table contains 4 entries. Next entry is 0 (16 bit mode), 1 (32 bit mode), 2 (64 bit mode).
ND_ILUT_DSIZE, // Table contains 4 entries. Next entry is 0 (16 bit size), 1 (32 bit size), 2 (64 bit size).
// This DOES NOT take into consideration forced/default sizes.
ND_ILUT_ASIZE, // Default addressing mode is used to transition
ND_ILUT_AUXILIARY, // Table contains 10 entries. Next entry is 0 (no prefix), 1 (rex), 2 (rex.w), etc.
ND_ILUT_AUXILIARY, // Table contains 8 entries. Next entry is 0 (no prefix), 1 (rex), 2 (rex.w), 3 (64 bit),
// 4 (default op size 16), 5 (default op size 32), 6 (default op size 64),
ND_ILUT_VENDOR, // Preferred vendor is used to transition. Default is entry 0. Otherwise, preferred
// vendor selects an alternate entry.
ND_ILUT_FEATURE, // Some instructions are mapped onto wide NOP space. They will be decoded only if the
// associated feature is set during decoding.
ND_ILUT_EX_M, // Table contains 32 entries. Next entry is vex/xop/evex.mmmmm
ND_ILUT_EX_PP, // Table contains 4 entries. Next entry is vex/xop/evex.pp
ND_ILUT_EX_L, // Table contains 4 entries. Next entry is vex/xop.l or evex.l'l
ND_ILUT_EX_W, // Table contains 2 entries. Next entry is vex/xop/evex.w
ND_ILUT_EX_WI, // Table contains 2 entries. Next entry is vex/xop/evex.w. If not in 64 bit, next entry is 0.
ND_ILUT_EX_ND, // Table contains 2 entries. Next entry is evex.ND.
ND_ILUT_EX_NF, // Table contains 2 entries. Next entry is evex.NF.
ND_ILUT_EX_SC, // Table contains 16 entries. Next entry is evex.SC.
ND_ILUT_VEX_MMMMM, // Table contains 32 entries. Next entry is vex/xop/evex.mmmmm
ND_ILUT_VEX_PP, // Table contains 4 entries. Next entry is vex/xop/evex.pp
ND_ILUT_VEX_L, // Table contains 4 entries. Next entry is vex/xop.l or evex.l'l
ND_ILUT_VEX_W, // Table contains 2 entries. Next entry is vex/xop/evex.w
ND_ILUT_VEX_WI, // Table contains 2 entries. Next entry is vex/xop/evex.w. If not in 64 bit, next entry is 0.
} ND_ILUT_TYPE;
@ -45,7 +43,7 @@ typedef enum _ND_ILUT_TYPE
#define ND_ILUT_INDEX_MOD_REG 1
// Mandatory prefixes.
#define ND_ILUT_INDEX_MAN_PREF_NP 0
#define ND_ILUT_INDEX_MAN_PREF_NONE 0
#define ND_ILUT_INDEX_MAN_PREF_66 1
#define ND_ILUT_INDEX_MAN_PREF_F3 2
#define ND_ILUT_INDEX_MAN_PREF_F2 3
@ -74,12 +72,10 @@ typedef enum _ND_ILUT_TYPE
#define ND_ILUT_INDEX_AUX_NONE 0
#define ND_ILUT_INDEX_AUX_REXB 1
#define ND_ILUT_INDEX_AUX_REXW 2
#define ND_ILUT_INDEX_AUX_MO64 3
#define ND_ILUT_INDEX_AUX_REPZ 4
#define ND_ILUT_INDEX_AUX_O64 3
#define ND_ILUT_INDEX_AUX_F3 4
#define ND_ILUT_INDEX_AUX_REP 5
#define ND_ILUT_INDEX_AUX_RIPREL 6
#define ND_ILUT_INDEX_AUX_REX2 7
#define ND_ILUT_INDEX_AUX_REX2W 8
// Specific features for instructions that map on the wide NOP space.
#define ND_ILUT_FEATURE_NONE 0
@ -89,6 +85,9 @@ typedef enum _ND_ILUT_TYPE
#define ND_ILUT_FEATURE_PITI 4
typedef struct _ND_TABLE
{
ND_UINT32 Type;
@ -131,10 +130,11 @@ typedef struct _ND_TABLE_MPREFIX
const void *Table[4];
} ND_TABLE_MPREFIX, *PND_TABLE_MPREFIX;
typedef struct _ND_TABLE_AUXILIARY
{
ND_UINT32 Type;
const void *Table[10];
const void *Table[8];
} ND_TABLE_AUXILIARY, *PND_TABLE_AUXILIARY;
typedef struct _ND_TABLE_VENDOR
@ -167,66 +167,65 @@ typedef struct _ND_TABLE_MODE
const void *Table[4];
} ND_TABLE_MODE, *PND_TABLE_MODE;
typedef struct _ND_TABLE_EX_M
typedef struct _ND_TABLE_VEX_MMMMM
{
ND_UINT32 Type;
const void *Table[32];
} ND_TABLE_EX_M, *PND_TABLE_EX_M;
} ND_TABLE_VEX_MMMMM, *PND_TABLE_VEX_MMMMM;
typedef struct _ND_TABLE_EX_PP
typedef struct _ND_TABLE_VEX_PP
{
ND_UINT32 Type;
const void *Table[4];
} ND_TABLE_EX_PP, *PND_TABLE_EX_PP;
} ND_TABLE_VEX_PP, *PND_TABLE_VEX_PP;
typedef struct _ND_TABLE_EX_L
typedef struct _ND_TABLE_VEX_L
{
ND_UINT32 Type;
const void *Table[4];
} ND_TABLE_EX_L, *PND_TABLE_EX_L;
typedef struct _ND_TABLE_EX_W
{
ND_UINT32 Type;
const void *Table[2];
} ND_TABLE_EX_W, *PND_TABLE_EX_W;
typedef struct _ND_TABLE_EX_ND
{
ND_UINT32 Type;
const void *Table[2];
} ND_TABLE_EX_ND, *PND_TABLE_EX_ND;
typedef struct _ND_TABLE_EX_NF
{
ND_UINT32 Type;
const void *Table[2];
} ND_TABLE_EX_NF, *PND_TABLE_EX_NF;
} ND_TABLE_VEX_L, *PND_TABLE_VEX_L;
typedef struct _ND_TABLE_EX_SC
typedef struct _ND_TABLE_VEX_W
{
ND_UINT32 Type;
const void *Table[16];
} ND_TABLE_EX_SC, *PND_TABLE_EX_SC;
const void *Table[8];
} ND_TABLE_VEX_W, *PND_TABLE_VEX_W;
//
// One instruction database entry.
// One instruction entry. This structure should be maintained bellow 2 cache lines in size (128 bytes).
//
typedef struct _ND_IDBE
#ifdef _MSC_VER
__declspec(align(128))
#pragma warning(push)
#pragma warning(disable: 4214)
#else
__attribute__((aligned(128)))
#endif
typedef struct _ND_INSTRUCTION
{
ND_UINT16 Instruction; // Instruction identifier. Check ND_INS_CLASS definitions.
ND_UINT8 Category; // Instruction category. Check ND_INS_TYPE.
ND_UINT8 IsaSet; // Instruction set. Check ND_INS_SET.
ND_UINT16 Mnemonic; // Mnemonic (index inside the global mnemonic table).
ND_UINT16 ValidPrefixes; // Accepted prefixes.
ND_UINT32 ValidModes; // Valid operating modes for the instruction.
ND_UINT8 ValidDecorators;// Accepted decorators (valid for EVEX instructions).
ND_UINT8 OpsCount; // Low 4 bits: explicit operands count; high 4 bits: implicit ops count.
ND_UINT8 TupleType; // EVEX tuple type.
ND_UINT8 ExcType; // SSE/VEX/EVEX/OPMASK/AMX/APX exception type.
ND_UINT8 ExcType : 5; // SSE/VEX/EVEX/OPMASK/AMX exception type.
ND_UINT8 ExcClass : 3; // Indicates the exception class (SSE/AVX, EVEX, OPMASK or AMX).
ND_UINT8 FpuFlags; // FPU status word C0, C1, C2 & C3 access type.
ND_UINT8 EvexMode; // EVEX prefix extension type.
ND_UINT8 Reserved2;
ND_UINT16 Reserved3;
ND_UINT32 Attributes; // Instruction attributes.
ND_UINT64 CpuidFlag; // Required CPUID feature flag.
// Per-flag access. Undefined flags will have their bit set in both the "Set" and "Cleared" mask, since a flag
// cannot be both cleared and set.
@ -235,14 +234,11 @@ typedef struct _ND_IDBE
ND_UINT32 SetFlags; // Flags that are always set to 1.
ND_UINT32 ClearedFlags; // Flags that are always cleared.
ND_UINT64 Attributes; // Instruction attributes.
ND_UINT64 CpuidFlag; // Required CPUID feature flag.
// List of operands. Up to 10 implicit and explicit operands stored in DB.
ND_UINT64 Operands[10];
} ND_IDBE, *PND_IDBE;
} ND_INSTRUCTION, *PND_INSTRUCTION;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
//
// The following definitions are per-operand specific.
@ -380,6 +376,7 @@ typedef enum _ND_OPERAND_TYPE_SPEC
ND_OPT_I,
ND_OPT_J,
ND_OPT_K,
ND_OPT_L,
ND_OPT_M,
ND_OPT_N,
@ -390,6 +387,7 @@ typedef enum _ND_OPERAND_TYPE_SPEC
ND_OPT_S,
ND_OPT_T,
ND_OPT_U,
ND_OPT_V,
ND_OPT_W,
ND_OPT_X,
@ -406,92 +404,91 @@ typedef enum _ND_OPERAND_TYPE_SPEC
ND_OPT_rT,
ND_OPT_mT,
ND_OPT_vT,
ND_OPT_dfv,
ND_OPT_1,
ND_OPT_CONST_1,
// These are implicit arguments inside instructions.
// Special registers.
ND_OPT_rIP,
ND_OPT_RIP,
ND_OPT_MXCSR,
ND_OPT_PKRU,
ND_OPT_SSP,
ND_OPT_UIF,
// General Purpose REgisters.
ND_OPT_AH,
ND_OPT_rAX,
ND_OPT_rCX,
ND_OPT_rDX,
ND_OPT_rBX,
ND_OPT_rSP,
ND_OPT_rBP,
ND_OPT_rSI,
ND_OPT_rDI,
ND_OPT_rR8,
ND_OPT_rR9,
ND_OPT_rR11,
ND_OPT_GPR_AH,
ND_OPT_GPR_rAX,
ND_OPT_GPR_rCX,
ND_OPT_GPR_rDX,
ND_OPT_GPR_rBX,
ND_OPT_GPR_rSP,
ND_OPT_GPR_rBP,
ND_OPT_GPR_rSI,
ND_OPT_GPR_rDI,
ND_OPT_GPR_rR8,
ND_OPT_GPR_rR9,
ND_OPT_GPR_rR11,
// Segment registers.
ND_OPT_CS,
ND_OPT_SS,
ND_OPT_DS,
ND_OPT_ES,
ND_OPT_FS,
ND_OPT_GS,
ND_OPT_SEG_CS,
ND_OPT_SEG_SS,
ND_OPT_SEG_DS,
ND_OPT_SEG_ES,
ND_OPT_SEG_FS,
ND_OPT_SEG_GS,
// FPU registers.
ND_OPT_ST0,
ND_OPT_STi,
ND_OPT_FPU_ST0,
ND_OPT_FPU_STX,
// SSE registers.
ND_OPT_XMM0,
ND_OPT_XMM1,
ND_OPT_XMM2,
ND_OPT_XMM3,
ND_OPT_XMM4,
ND_OPT_XMM5,
ND_OPT_XMM6,
ND_OPT_XMM7,
ND_OPT_SSE_XMM0,
ND_OPT_SSE_XMM1,
ND_OPT_SSE_XMM2,
ND_OPT_SSE_XMM3,
ND_OPT_SSE_XMM4,
ND_OPT_SSE_XMM5,
ND_OPT_SSE_XMM6,
ND_OPT_SSE_XMM7,
// Implicit memory operands.
ND_OPT_pAX, // [rAX]
ND_OPT_pCX, // [rCX]
ND_OPT_pBXAL, // [rBX + AL]
ND_OPT_pDI, // [rDI]
ND_OPT_SHS, // Shadow stack.
ND_OPT_SHSP, // Shadow stack pointed by the SSP.
ND_OPT_SHS0, // Shadow stack pointed by the SSP.
ND_OPT_SMT, // Source MSR table, encoded in [RSI].
ND_OPT_DMT, // Destination MSR table, encoded in [RDI].
ND_OPT_MEM_rAX, // [rAX]
ND_OPT_MEM_rCX, // [rCX]
ND_OPT_MEM_rBX_AL, // [rBX + AL]
ND_OPT_MEM_rDI, // [rDI]
ND_OPT_MEM_SHS, // Shadow stack.
ND_OPT_MEM_SHSP, // Shadow stack pointed by the SSP.
ND_OPT_MEM_SHS0,
ND_OPT_MEM_SMSRT, // Source MSR table, encoded in [RSI].
ND_OPT_MEM_DMSRT, // Destination MSR table, encoded in [RDI].
// Special immediates.
ND_OPT_m2zI,
ND_OPT_Im2z,
// Misc CR/XCR/MSR/SYS registers.
ND_OPT_CR0,
ND_OPT_IDTR,
ND_OPT_GDTR,
ND_OPT_LDTR,
ND_OPT_TR,
ND_OPT_X87CONTROL,
ND_OPT_X87TAG,
ND_OPT_X87STATUS,
ND_OPT_CR_0,
ND_OPT_SYS_IDTR,
ND_OPT_SYS_GDTR,
ND_OPT_SYS_LDTR,
ND_OPT_SYS_TR,
ND_OPT_X87_CONTROL,
ND_OPT_X87_TAG,
ND_OPT_X87_STATUS,
ND_OPT_MSR,
ND_OPT_XCR,
ND_OPT_TSC,
ND_OPT_TSCAUX,
ND_OPT_SEIP,
ND_OPT_SESP,
ND_OPT_SCS,
ND_OPT_STAR,
ND_OPT_LSTAR,
ND_OPT_FMASK,
ND_OPT_FSBASE,
ND_OPT_GSBASE,
ND_OPT_KGSBASE,
ND_OPT_XCR0,
ND_OPT_BANK,
ND_OPT_MSR_TSC,
ND_OPT_MSR_TSCAUX,
ND_OPT_MSR_SEIP,
ND_OPT_MSR_SESP,
ND_OPT_MSR_SCS,
ND_OPT_MSR_STAR,
ND_OPT_MSR_LSTAR,
ND_OPT_MSR_FMASK,
ND_OPT_MSR_FSBASE,
ND_OPT_MSR_GSBASE,
ND_OPT_MSR_KGSBASE,
ND_OPT_XCR_0,
ND_OPT_REG_BANK,
} ND_OPERAND_TYPE_SPEC;
@ -499,9 +496,9 @@ typedef enum _ND_OPERAND_TYPE_SPEC
//
// Operand flags.
//
#define ND_OPF_OPDEF 0x01 // The operand is default, no need to show it in disassembly.
#define ND_OPF_OPSIGNEXO1 0x02 // The operand is sign-extended to the first operands' size.
#define ND_OPF_OPSIGNEXDW 0x04 // The operand is sign-extended to the default word size.
#define ND_OPF_DEFAULT 0x01 // The operand is default, no need to show it in disassembly.
#define ND_OPF_SEX_OP1 0x02 // The operand is sign-extended to the first operands' size.
#define ND_OPF_SEX_DWS 0x04 // The operand is sign-extended to the default word size.
//
@ -523,7 +520,7 @@ typedef enum _ND_OPERAND_TYPE_SPEC
// Operand decorator flags.
//
#define ND_OPD_MASK 0x01 // Mask accepted.
#define ND_OPD_ZERO 0x02 // Zeroing accepted.
#define ND_OPD_Z 0x02 // Zeroing accepted.
#define ND_OPD_B32 0x04 // 32 bit broadcast supported.
#define ND_OPD_B64 0x08 // 64 bit broadcast supported.
#define ND_OPD_SAE 0x10 // Suppress all exceptions supported.
@ -536,13 +533,13 @@ typedef enum _ND_OPERAND_TYPE_SPEC
//
// Include auto-generated stuff.
//
#include "../../inc/bdx86_constants.h"
#include "bdx86_mnemonics.h"
#include "bdx86_instructions.h"
#include "bdx86_prefixes.h"
#include "bdx86_table_root.h"
#include "bdx86_table_xop.h"
#include "bdx86_table_vex.h"
#include "bdx86_table_evex.h"
#endif // BDX86_TABLEDEFS_H
#include "mnemonics.h"
#include "../../inc/constants.h"
#include "instructions.h"
#include "prefixes.h"
#include "table_root.h"
#include "table_xop.h"
#include "table_vex.h"
#include "table_evex.h"
#endif // TABLEDEFS_H

@ -1,7 +1,7 @@
# Disassembler Tests
These tests are used to validate bddisasm. Each test consists of up to three files:
* The binary test file. The name format for this type of file is `name_16|32|64.test`. 16/32/64 indicates disassembly mode
* The binary test file. The name format for this type of file is `name_16|32|64`. No extension must be provided; 16/32/64 indicates disassembly mode
* The output result file. Must be named the same as the binary test file, but with the extension .result
* Optional assembly file, used to generate the binary test file

File diff suppressed because it is too large Load Diff

@ -1,224 +0,0 @@
0000000000000000 626c7808fc1e AADD dword ptr [r22], r27d
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 4, RawSize: 4, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 27, RegCount: 1
0000000000000006 626cf808fc1e AADD qword ptr [r22], r27
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
000000000000000C 626c7908fc1e AAND dword ptr [r22], r27d
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 4, RawSize: 4, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 27, RegCount: 1
0000000000000012 626cf908fc1e AAND qword ptr [r22], r27
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
0000000000000018 626c7b08fc1e AOR dword ptr [r22], r27d
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 4, RawSize: 4, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 27, RegCount: 1
000000000000001E 626cfb08fc1e AOR qword ptr [r22], r27
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
0000000000000024 626c7a08fc1e AXOR dword ptr [r22], r27d
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 4, RawSize: 4, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 27, RegCount: 1
000000000000002A 626cfa08fc1e AXOR qword ptr [r22], r27
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: RAO-INT, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-RAO-INT
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 22,
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
0000000000000030 626c7b08f8de URDMSR r22, r27
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-USER-MSR
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 22, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
0000000000000036 62ff7b08f8c6bdbdbdbd URDMSR r22, 0xbdbdbdbd
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 22, RegCount: 1
Operand: 1, Acc: R-, Type: Immediate, Size: 4, RawSize: 4, Encoding: I
Operand: 2, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1
0000000000000040 626c7a08f8de UWRMSR r27, r22
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Exception class: APX, exception type: APX-EVEX-USER-MSR
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 27, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 22, RegCount: 1
0000000000000046 62ff7a08f8c6bdbdbdbd UWRMSR 0xbdbdbdbd, r22
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
EVEX Tuple Type: None
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Immediate, Size: 4, RawSize: 4, Encoding: I
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 22, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1

@ -1 +0,0 @@
blxüblřüblyüblůübl{üblűüblzüblúübl{řŢb˙{řĆ˝˝˝˝blzřŢb˙zřĆ˝˝˝˝

@ -1,16 +0,0 @@
bits 64
; NF not supported.
db 0x62, 0x6C, 0x78, 0x0C, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; V' set.
db 0x62, 0x6C, 0x78, 0x00, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; VVVV set.
db 0x62, 0x6C, 0x38, 0x08, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; Reserved bits set.
db 0x62, 0x6C, 0x78, 0x09, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
db 0x62, 0x6C, 0x78, 0x88, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; Invalid PUSH2 register (RSP).
db 0x62, 0x6C, 0x58, 0x18, 0xFF, 0xF4, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
; Invalid POP2 registers (same dest register, RAX).
db 0x62, 0x64, 0x78, 0x18, 0x8F, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,

@ -1,7 +0,0 @@
0000000000000000 62 db 0x62 (0x80000002)
0000000000000010 62 db 0x62 (0x80000040)
0000000000000020 62 db 0x62 (0x80000032)
0000000000000030 62 db 0x62 (0x80000045)
0000000000000040 62 db 0x62 (0x80000045)
0000000000000050 62 db 0x62 (0x80000044)
0000000000000060 62 db 0x62 (0x80000044)

@ -1,25 +0,0 @@
bits 64
; REX2 with REX
db 0x48, 0xD5, 0x00, 0x33, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; REX with REX2
db 0xD5, 0x00, 0x48, 0x33, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; REX2 with EVEX
db 0xD5, 0x00, 0x62, 0x6C, 0x78, 0x08, 0x10, 0x1E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; JMPABS with prefixes
db 0x66, 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x90, 0x90, 0x90, 0x90
db 0x67, 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x90, 0x90, 0x90, 0x90
db 0xF2, 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x90, 0x90, 0x90, 0x90
db 0xF3, 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x90, 0x90, 0x90, 0x90
; REX2 with unssuported instruction
db 0xD5, 0x00, 0x70, 0xBD, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0x80, 0x80, 0xBD, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; REX2 inside legacy map 0x38 & 0x3A
db 0xD5, 0x80, 0x38, 0xFC, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0x80, 0x3A, 0xCC, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
; REX2 with extension opcode.
db 0xD5, 0x7F, 0x0F, 0xD1, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0x7F, 0x0F, 0x38, 0x00, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0xFF, 0x38, 0x00, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90

@ -1,14 +0,0 @@
0000000000000000 48 db 0x48 (0x80000004)
0000000000000010 d5 db 0xd5 (0x80000009)
0000000000000020 d5 db 0xd5 (0x80000009)
0000000000000030 66 db 0x66 (0x80000002)
0000000000000040 67 db 0x67 (0x80000002)
0000000000000050 f2 db 0xf2 (0x80000002)
0000000000000060 f3 db 0xf3 (0x80000002)
0000000000000070 d5 db 0xd5 (0x80000002)
0000000000000080 d5 db 0xd5 (0x80000002)
0000000000000090 d5 db 0xd5 (0x80000002)
00000000000000A0 d5 db 0xd5 (0x80000002)
00000000000000B0 d5 db 0xd5 (0x80000002)
00000000000000C0 d5 db 0xd5 (0x80000002)
00000000000000D0 d5 db 0xd5 (0x80000002)

@ -1,32 +0,0 @@
bits 64
; REX2 0
db 0xD5, 0x00, 0x33, 0xC0
; REX2.W = 1
db 0xD5, 0x08, 0x33, 0xC0
; REX2.B3 & REX2.B4 set
db 0xD5, 0x19, 0x33, 0xC0
; REX2.R3 & REX2.R4 set
db 0xD5, 0x4C, 0x33, 0xC0
; REX2.X3 & REX2.X4 set, no memory
db 0xD5, 0x2A, 0x33, 0xC0
; REX2.X3 & REX2.X4 set, SIB access
db 0xD5, 0x2A, 0x33, 0x04, 0x33
; JMPABS
db 0xD5, 0x00, 0xA1, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD
; PUSHP/POPP
db 0xD5, 0x08, 0x50
db 0xD5, 0x08, 0x58
db 0xD5, 0x18, 0x50
db 0xD5, 0x18, 0x58
; PUSH/POP
db 0xD5, 0x00, 0x50
db 0xD5, 0x00, 0x58
db 0xD5, 0x10, 0x50
db 0xD5, 0x10, 0x58
; NOP
db 0xD5, 0x00, 0x90
; XCHG r16, rax
db 0xD5, 0x18, 0x90
; RDFSBASE r31
db 0xF3, 0xD5, 0x99, 0xAE, 0xC7

@ -1,301 +0,0 @@
0000000000000000 d50033c0 XOR eax, eax
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 4, RawSize: 4, Encoding: R, RegType: General Purpose, RegSize: 4, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 4, RawSize: 4, Encoding: M, RegType: General Purpose, RegSize: 4, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 4, RawSize: 4, Encoding: S, RegType: Flags, RegSize: 4, RegId: 0, RegCount: 1
0000000000000004 d50833c0 XOR rax, rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
0000000000000008 d51933c0 XOR rax, r24
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 24, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
000000000000000C d54c33c0 XOR r24, rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 24, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
0000000000000010 d52a33c0 XOR rax, rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
0000000000000014 d52a330433 XOR rax, qword ptr [rbx+r30]
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: LOGIC, CET tracked: no
FLAGS access
CF: 0, PF: m, AF: u, ZF: m, SF: m, OF: 0,
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: M,
Segment: 3, Base: 3, Index: 30 * 1,
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
0000000000000019 d500a1bdbdbdbdbdbdbdbd JMPABS 0xbdbdbdbdbdbdbdbd
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: UNCOND_BR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Address, Size: 8, RawSize: 8, Encoding: D
Operand: 1, Acc: -W, Type: Register, Size: 4, RawSize: 4, Encoding: S, RegType: IP, RegSize: 4, RegId: 0, RegCount: 1
0000000000000024 d50850 PUSHP rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: PUSH, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: -W, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000027 d50858 POPP rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: POP, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
000000000000002A d51850 PUSHP r16
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: PUSH, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: -W, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
000000000000002D d51858 POPP r16
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: APX_F, Ins cat: POP, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 21
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000030 d50050 PUSH rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: PUSH, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: -W, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000033 d50058 POP rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: POP, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000036 d51050 PUSH r16
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: PUSH, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: -W, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
0000000000000039 d51058 POP r16
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: POP, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: R-, Type: Memory, Size: 8, RawSize: 8, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
000000000000003C d50090 NOP
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: NOP, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
000000000000003F d51890 XCHG r16, rax
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: I86, Ins cat: DATAXFER, CET tracked: no
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: O, RegType: General Purpose, RegSize: 8, RegId: 16, RegCount: 1
Operand: 1, Acc: RW, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
0000000000000042 f3d599aec7 RDFSBASE r31
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: RDWRFSGS, Ins cat: RDWRFSGS, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000000, reg: ebx, bit: 0
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 31, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Model Specific, RegSize: 8, RegId: 0xc0000100, RegCount: 1

@ -2,7 +2,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -24,7 +24,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -46,7 +46,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -68,7 +68,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -90,7 +90,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -112,7 +112,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -134,7 +134,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -156,7 +156,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -178,7 +178,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -200,7 +200,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -222,7 +222,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -244,7 +244,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -266,7 +266,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -288,7 +288,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -310,7 +310,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -332,7 +332,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -354,7 +354,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -376,7 +376,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -398,7 +398,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -420,7 +420,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -442,7 +442,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -464,7 +464,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -486,7 +486,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -508,7 +508,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -530,7 +530,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -552,7 +552,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -574,7 +574,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -596,7 +596,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -618,7 +618,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -640,7 +640,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -662,7 +662,7 @@
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes
@ -684,7 +684,7 @@
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: CMPCCXADD, Ins cat: CMPCCXADD, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 7
Exception class: SSE/VEX, exception type: 14
Exception class: EVEX, exception type: E6NF
FLAGS access
CF: m, PF: m, AF: m, ZF: m, SF: m, OF: m,
Valid modes

@ -13,11 +13,11 @@
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Segment, RegSize: 8, RegId: 1, RegCount: 1
Operand: 1, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: IP, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
Operand: 3, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Segment, RegSize: 8, RegId: 2, RegCount: 1
Operand: 4, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: General Purpose, RegSize: 8, RegId: 4, RegCount: 1
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: IP, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Flags, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: General Purpose, RegSize: 8, RegId: 4, RegCount: 1
Operand: 3, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Segment, RegSize: 8, RegId: 1, RegCount: 1
Operand: 4, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: Segment, RegSize: 8, RegId: 2, RegCount: 1
Operand: 5, Acc: R-, Type: Memory, Size: 40, RawSize: 40, Encoding: S, Stack: yes,
Segment: 2, Base: 4,
Operand: 6, Acc: CRCW, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: SSP, RegSize: 8, RegId: 0, RegCount: 1

@ -24,8 +24,8 @@
db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD4, 0x90 ; AAM
db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
;db 0xD5, 0x90 ; AAD
;db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0xD5, 0x90 ; AAD
db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0x60 ; PUSHA
db 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
db 0x61 ; POPA

@ -10,7 +10,8 @@
0000000000000090 37 db 0x37 (0x80000009)
00000000000000A0 3f db 0x3f (0x80000009)
00000000000000B0 d4 db 0xd4 (0x80000009)
00000000000000C0 60 db 0x60 (0x80000009)
00000000000000D0 61 db 0x61 (0x80000009)
00000000000000E0 9a db 0x9a (0x80000009)
00000000000000F0 ea db 0xea (0x80000009)
00000000000000C0 d5 db 0xd5 (0x80000009)
00000000000000D0 60 db 0x60 (0x80000009)
00000000000000E0 61 db 0x61 (0x80000009)
00000000000000F0 9a db 0x9a (0x80000009)
0000000000000100 ea db 0xea (0x80000009)

@ -1 +1 @@
<06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>7<EFBFBD><37><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ô<EFBFBD><C394><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`<60><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a<EFBFBD><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>š<EFBFBD><C5A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ê<EFBFBD><C3AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<06><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><16><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>7<EFBFBD><37><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ô<EFBFBD><C394><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Õ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`<60><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a<EFBFBD><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>š<EFBFBD><C5A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ê<EFBFBD><C3AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

@ -1,11 +0,0 @@
bits 64
; UWRMSR 0x44332211, rax
db 0xC4, 0xE7, 0x7A, 0xF8, 0xC0, 0x11, 0x22, 0x33, 0x44
; URDMSR rax, 0x44332211
db 0xC4, 0xE7, 0x7B, 0xF8, 0xC0, 0x11, 0x22, 0x33, 0x44
; UWRMSR rcx, rax
db 0xF3, 0x0F, 0x38, 0xF8, 0xC1
; URDMSR rax, rcx
db 0xF2, 0x0F, 0x38, 0xF8, 0xC1

@ -1,68 +0,0 @@
0000000000000000 c4e77af8c011223344 UWRMSR 0x44332211, rax
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: USER_MSR, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 15
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Immediate, Size: 4, RawSize: 4, Encoding: I
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1
0000000000000009 c4e77bf8c011223344 URDMSR rax, 0x44332211
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: USER_MSR, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 15
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Immediate, Size: 4, RawSize: 4, Encoding: I
Operand: 2, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1
0000000000000012 f30f38f8c1 UWRMSR rax, rcx
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: USER_MSR, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 15
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 1, RegCount: 1
Operand: 2, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1
0000000000000017 f20f38f8c1 URDMSR rcx, rax
DSIZE: 32, ASIZE: 64, VLEN: -
ISA Set: USER_MSR, Ins cat: USER_MSR, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: edx, bit: 15
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: no, V8086: no, Prot: no, Compat: no, Long: yes
SMM on: yes, SMM off: yes, SGX on: yes, SGX off: yes, TSX on: yes, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: yes
Valid prefixes
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: M, RegType: General Purpose, RegSize: 8, RegId: 1, RegCount: 1
Operand: 1, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: R, RegType: General Purpose, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: R-, Type: Register, Size: 8, RawSize: 8, Encoding: E, RegType: Model Specific, RegSize: 8, RegId: 0xffffffff, RegCount: 1

@ -1 +0,0 @@
Δηzψΐ"3DΔη{ψΐ"3DσΑςΑ

@ -1,6 +1,6 @@
.PHONY: clean
SRC_FILES := bdshemu.c bdshemu_x86.c
SRC_FILES := bdshemu.c
OBJECTS := $(SRC_FILES:.c=.o)
@ -120,5 +120,4 @@ install: all
install -d $(DESTDIR)$(PREFIX)/lib/
install -m 644 $(OUT_DIR)/$(LIB_NAME) $(DESTDIR)$(PREFIX)/lib/
install -d $(DESTDIR)$(PREFIX)/include/bddisasm/
cp -r ../inc/bdshemu.h $(DESTDIR)$(PREFIX)/include/bddisasm/
cp -r ../inc/bdshemu_x86.h $(DESTDIR)$(PREFIX)/include/bddisasm/
cp -r ../inc/bdshemu.h $(DESTDIR)$(PREFIX)/include/bddisasm/

File diff suppressed because it is too large Load Diff

@ -643,13 +643,10 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="bdshemu.c" />
<ClCompile Include="bdshemu_x86.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\inc\bddisasm_version.h" />
<ClInclude Include="..\inc\bdshemu.h" />
<ClInclude Include="..\inc\bdshemu_x86.h" />
<ClInclude Include="include\bdshemu_common.h" />
<ClInclude Include="..\inc\version.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

@ -16,36 +16,18 @@
<Filter Include="Header Files\public">
<UniqueIdentifier>{e9031566-ae16-49a2-807a-b33729f7b1d4}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\public\x86">
<UniqueIdentifier>{d95202e3-5db7-4437-aaee-b42dd317eb1b}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\x86">
<UniqueIdentifier>{b37ad850-b053-4c49-a61c-81abc50c144e}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\private">
<UniqueIdentifier>{ca0d8798-3c56-489f-8cc5-fe315397c76a}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="bdshemu.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\inc\bdshemu.h">
<Filter>Header Files\public</Filter>
</ClInclude>
<ClInclude Include="..\inc\bdshemu_x86.h">
<Filter>Header Files\public\x86</Filter>
</ClInclude>
<ClInclude Include="include\bdshemu_common.h">
<Filter>Header Files\private</Filter>
</ClInclude>
<ClInclude Include="..\inc\bddisasm_version.h">
<ClInclude Include="..\inc\version.h">
<Filter>Header Files\public</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="bdshemu.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bdshemu_x86.c">
<Filter>Source Files\x86</Filter>
</ClCompile>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

@ -1,172 +0,0 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BDSHEMU_COMMON_H_
#define BDSHEMU_COMMON_H_
#if defined(_MSC_VER)
#include <sal.h>
#else
#define _Analysis_assume_(x)
#endif
// The SHELLBMP and STACKBMP are two bitmaps which hold the state of each shellcode byte and each stack byte.
// Inside SHELLBMP, we store whether a shellcode byte has been fetched for execution or not, and whether it was
// modified or not.
// Inside STACKBMP, we store whether a stack byte is part of a previously saved RIP value or not.
#define STACKBMP(ctx) ((ctx)->Intbuf)
#define STACKBMP_SIZE(ctx) ((ctx)->StackSize)
#define SHELLBMP(ctx) (!((ctx)->Options & SHEMU_OPT_DIRECT_MAPPED_SHELL) ? (ctx)->Intbuf + (ctx)->StackSize : ND_NULL)
#define SHELLBMP_SIZE(ctx) (!((ctx)->Options & SHEMU_OPT_DIRECT_MAPPED_SHELL) ? (ctx)->ShellcodeSize : 0)
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define MIN(a, b) ((a) > (b) ? (b) : (a))
// Flags used for the shellcode. These are set inside SHELLBMP. Each byte at index X inside SHELLBMP indicates the state
// of the shellcode byte at index X.
#define SHELL_BYTE_DIRTY (0x01) // The location inside the shellcode has been written.
#define SHELL_BYTE_FETCHED (0x02) // The location inside the shellcode has been fetched for execution.
#define SHELL_BYTE_IBYTES (0x04) // The location inside the shellcode represents executed instruction
// bytes. Does not include the first instruction byte, which is marked
// using the SHELL_BYTE_FETCHED flag.
// Flags used for the stack. These are set inside STACKBMP. Each byte at index X inside STACKBMP indicates the state
// of the stack byte at index X.
#define STACK_BYTE_RIP (0x01) // The location inside the stack contains a RIP portion.
// Flags used for the GPR tracking mechanism. Each byte X inside the GPR tracker array indicates the state of said GPR.
#define GPR_TRACK_READ (0x01) // The GPR has been read, by any instruction (including RMW).
#define GPR_TRACK_DIRTY (0x02) // The GPR has been modified.
#define GET_BITS(val, start, stop) (((val) >> (start)) & ((1ULL << ((stop) - (start) + 1)) - 1))
#define ShemuShellBmpStateSet(Context, Start, Count, Flags) \
ShemuBmpStateUpdate(SHELLBMP(Context), SHELLBMP_SIZE(Context), Start, Count, Flags, ND_FALSE)
#define ShemuShellBmpStateClear(Context, Start, Count, Flags) \
ShemuBmpStateUpdate(SHELLBMP(Context), SHELLBMP_SIZE(Context), Start, Count, Flags, ND_TRUE)
#define ShemuShellBmpStateCheck(Context, Start, Count, Flags) \
ShemuBmpStateCheck(SHELLBMP(Context), SHELLBMP_SIZE(Context), Start, Count, Flags)
#define ShemuStackBmpStateSet(Contxt, Start, Count, Flags) \
ShemuBmpStateUpdate(STACKBMP(Context), STACKBMP_SIZE(Context), Start, Count, Flags, ND_FALSE)
#define ShemuStackBmpStateClear(Context, Start, Count, Flags) \
ShemuBmpStateUpdate(STACKBMP(Context), STACKBMP_SIZE(Context), Start, Count, Flags, ND_TRUE)
#define ShemuStackBmpStateCheck(Context, Start, Count, Flags) \
ShemuBmpStateCheck(STACKBMP(Context), STACKBMP_SIZE(Context), Start, Count, Flags)
void
shemu_printf(
SHEMU_CONTEXT *Context,
char *formatstring,
...
);
void *
shemu_memcpy(
void *Dest,
const void *Source,
ND_SIZET Size
);
void
ShemuHexlify(
ND_UINT8 *Value,
ND_UINT64 ValueSize,
char *Hex,
ND_UINT64 HexSize
);
void
ShemuBmpStateUpdate(
ND_UINT8 *Bitmap,
ND_UINT64 Size,
ND_UINT64 Start,
ND_UINT64 Count,
ND_UINT8 Flags,
ND_BOOL Clear
);
ND_BOOL
ShemuBmpStateCheck(
ND_UINT8 *Bitmap,
ND_UINT64 Size,
ND_UINT64 Start,
ND_UINT64 Count,
ND_UINT8 Flags
);
ND_BOOL
ShemuIsShellcodePtr(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size
);
ND_BOOL
ShemuIsStackPtr(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size
);
ND_BOOL
ShemuIsIcachePtr(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size
);
SHEMU_STATUS
ShemuMemLoad(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size,
ND_UINT8 *Value
);
SHEMU_STATUS
ShemuMemStore(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size,
ND_UINT8 *Value
);
SHEMU_STATUS
ShemuMemFetch(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size,
ND_UINT8 *Bytes
);
void
ShemuFlushIcache(
SHEMU_CONTEXT *Context
);
void
ShemuDisplayMemValue(
SHEMU_CONTEXT *Context,
ND_UINT64 Gla,
ND_UINT64 Size,
ND_UINT8 *Value,
ND_BOOL Load
);
ND_BOOL
ShemuIsImmMetasploitHash(
ND_UINT64 Value
);
#endif // BDSHEMU_COMMON_H_

@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.16)
option(BDD_FUZZ_WITH_LOGS "Enable logging for the fuzzer" OFF)
option(BDD_FUZZ_DIRECT_MAP "Enable direct SHEMU_OPT_DIRECT_MAPPED_SHELL" OFF)
project(bdshemu_fuzzer LANGUAGES C)
@ -18,23 +17,4 @@ if (BDD_FUZZ_WITH_LOGS)
target_compile_definitions(shfuzzx64 PRIVATE ENABLE_LOGGING)
endif (BDD_FUZZ_WITH_LOGS)
if (BDD_FUZZ_DIRECT_MAP)
target_compile_definitions(shfuzzx86 PRIVATE DIRECT_MAP)
target_compile_definitions(shfuzzx64 PRIVATE DIRECT_MAP)
endif (BDD_FUZZ_DIRECT_MAP)
# Using CMAKE_C_COMPILER_ID to check for this will not work because afl-gcc is reported as gcc, while afl-clang and
# afl-clang-fast are reported as clang.
# We also don't want to use libfuzzer with AFL because it seems to have some build issues.
# TODO: but it should work, see https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/AFL_integration.md#how
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" AND NOT "${CMAKE_C_COMPILER}" MATCHES "afl-.*")
message(STATUS "Will use libfuzzer")
target_compile_options(shfuzzx86 PRIVATE -fsanitize=fuzzer)
target_link_libraries(shfuzzx86 PRIVATE -fsanitize=fuzzer)
target_compile_options(shfuzzx64 PRIVATE -fsanitize=fuzzer)
target_link_libraries(shfuzzx64 PRIVATE -fsanitize=fuzzer)
endif ()
add_custom_target(shfuzz DEPENDS shfuzzx86 shfuzzx64)

@ -0,0 +1,49 @@
# Bitdefender Shellocde Emulator Fuzzer
This assumes that you have [AFL](https://github.com/google/AFL) in your path.
It collects the `bddisasm` and `bdshemu` sources into a single executable, built with AFL instrumentation.
## Getting started
Build it with `make shfuzz`.
Start fuzzing with `make fuzz32` (for 32-bit mode samples) or `make fuzz64` (for 64-bit mode samples).
If you're in a hurry you can fuzz in the quick and dirty mode with `DIRTY=y`: `make fuzz32 DIRTY=y` or `make fuzz64 DIRTY=y`.
Activate support for [address sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) with `AFL_USE_ASAN=1 make shfuzz`. This can uncover more bugs, but it is a lot slower and requires more memory.
Input files are in the `in-32` and `in-64` directories, crashes will be in `out-32/crashes` or `out-64/crashes`, hangs will be in `out-32/hangs` or `out-64/hangs`.
## Details
If the `AFL_COMPILER` variable is not set, the build process looks for `afl-clang-fast` and if it is available, the tool is compiled with that. If not, it tries to choose between `afl-clang` and `afl-gcc`.
If you want to use a certain compiler simply set `AFL_COMPILER` before invoking make: `AFL_COMPILER=afl-gcc make`.
Note that `afl-clang-fast` is not compiled by default when compiling AFL. See [llvm mode](https://github.com/google/AFL/tree/master/llvm_mode) in the AFL repository.
Run the fuzzer in 32-bit mode with `make fuzz32`, or in 64-bit mode with `make fuzz64`.
If you want to take advantage of multiple cores see [parallel fuzzing](https://github.com/google/AFL/blob/master/docs/parallel_fuzzing.txt).
If `afl-clang-fast` is used, we try to use AFL in persistent mode, which should provide better performance.
Note that both `fuzz32` and `fuzz64` assume that the tool was compiled with `afl-clang-fast`, `afl-clang`, or `afl-gcc`.
ASAN builds will have increased memory requirements. You may need to tweak the `-m` parameter (or set `AFL_MEMORY`) for `afl-fuzz` (see [notes for ASAN](https://github.com/google/AFL/blob/master/docs/notes_for_asan.txt)).
By default, all logging is disabled, as it is already not visible while AFL is running. Compile with `LOG=y` in order to enable some minimal logging.
## Using the tool
The `shfuzz` tool is a simplified version of `disasmtool`. It takes 3 positional arguments:
```bash
shfuzz file mode use_logging
```
- file - the path to a input file that contains instructions to be disassembled and emulated;
- mode - the mode in which to run: `32` for 32-bit instructions, `64` for 64-bit instruction;
- use_logging - if present, will actually log everything that `bdshemu` wants to log; even if absent, the `ShemuLog` implementation will still try to access every character in the string it should normally print, so if you want to find bugs related to logging you can still do, but it is a lot faster when the strings don't get printed. This is ignored if you compile `shfuzz` without `LOG=y`.
Any errors encountered while parsing the arguments, trying to open the input file, or allocate memory are handled by calling `abort()`. This makes it easier to detect these problems.

@ -25,37 +25,11 @@
#define LOG(fmt, ...)
#endif // ENABLE_LOGGING
#define DEFAULT_OPTIONS (SHEMU_OPT_TRACE_EMULATION |\
SHEMU_OPT_SUPPORT_AES |\
SHEMU_OPT_SUPPORT_APX)
void ShemuLog(char *data, void *ctx)
void ShemuLog(char *data)
{
(void)(ctx);
LOG("%s", data);
}
ND_BOOL
access_shellcode(void *Ctx, ND_UINT64 Gla, ND_SIZET Size, ND_UINT8 *Buffer, ND_BOOL Store)
{
SHEMU_CONTEXT *ctx = Ctx;
ND_UINT32 offset;
offset = (ND_UINT32)(Gla - ctx->ShellcodeBase);
if (Store)
{
memcpy(ctx->Shellcode + offset, Buffer, Size);
}
else
{
memcpy(Buffer, ctx->Shellcode + offset, Size);
}
return true;
}
#if defined(FUZZ_X86) || defined(FUZZ_X64)
#ifdef FUZZ_X86
#define DEF_CODE ND_CODE_32
#define FUZZER_TYPE "x86"
@ -71,13 +45,6 @@ void run_shemu(uint8_t *Data, size_t Size)
SHEMU_CONTEXT ctx = { 0 };
SHEMU_STATUS shs;
#if defined(DIRECT_MAP)
ctx.AccessShellcode = access_shellcode;
ctx.Options |= SHEMU_OPT_DIRECT_MAPPED_SHELL;
#endif
ctx.ArchType = SHEMU_ARCH_TYPE_X86;
ctx.Shellcode = Data;
ctx.Stack = calloc(1, 0x2000);
@ -98,28 +65,28 @@ void run_shemu(uint8_t *Data, size_t Size)
ctx.ShellcodeSize = (uint32_t)Size;
ctx.StackBase = 0x100000;
ctx.StackSize = 0x2000;
ctx.Arch.X86.Registers.RegRsp = 0x101000;
ctx.Registers.RegRsp = 0x101000;
ctx.IntbufSize = (uint32_t)Size + 0x2000;
ctx.Arch.X86.Registers.RegFlags = NDR_RFLAG_IF | 2;
ctx.Arch.X86.Registers.RegRip = ctx.ShellcodeBase;
ctx.Arch.X86.Segments.Cs.Selector = 0x10;
ctx.Arch.X86.Segments.Ds.Selector = 0x28;
ctx.Arch.X86.Segments.Es.Selector = 0x28;
ctx.Arch.X86.Segments.Ss.Selector = 0x28;
ctx.Arch.X86.Segments.Fs.Selector = 0x30;
ctx.Arch.X86.Segments.Fs.Base = 0x7FFF0000;
ctx.Arch.X86.Segments.Gs.Selector = 0x30;
ctx.Arch.X86.Segments.Gs.Base = 0x7FFF0000;
ctx.Arch.X86.Mode = DEF_CODE;
ctx.Arch.X86.Ring = 3;
ctx.TibBase = ctx.Arch.X86.Mode == ND_CODE_32 ? ctx.Arch.X86.Segments.Fs.Base : ctx.Arch.X86.Segments.Gs.Base;
ctx.Registers.RegFlags = NDR_RFLAG_IF | 2;
ctx.Registers.RegRip = ctx.ShellcodeBase;
ctx.Segments.Cs.Selector = 0x10;
ctx.Segments.Ds.Selector = 0x28;
ctx.Segments.Es.Selector = 0x28;
ctx.Segments.Ss.Selector = 0x28;
ctx.Segments.Fs.Selector = 0x30;
ctx.Segments.Fs.Base = 0x7FFF0000;
ctx.Segments.Gs.Selector = 0x30;
ctx.Segments.Gs.Base = 0x7FFF0000;
ctx.Mode = DEF_CODE;
ctx.Ring = 3;
ctx.TibBase = ctx.Mode == ND_CODE_32 ? ctx.Segments.Fs.Base : ctx.Segments.Gs.Base;
ctx.MaxInstructionsCount = 4096;
ctx.Log = &ShemuLog;
ctx.Flags = 0;
ctx.Options |= DEFAULT_OPTIONS;
ctx.Options = SHEMU_OPT_TRACE_EMULATION;
shs = ShemuEmulate(&ctx);
LOG("[+] Shemu returned: 0x%08x\n", shs);
@ -127,11 +94,10 @@ void run_shemu(uint8_t *Data, size_t Size)
free(ctx.Intbuf);
free(ctx.Stack);
}
#else
#error "Do not know what to fuzz, define one of FUZZ_X86, FUZZ_X64"
#endif
#if defined(__AFL_FUZZ_TESTCASE_LEN)
#include <unistd.h>
// See https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md
__AFL_FUZZ_INIT();

@ -1,21 +0,0 @@
#!/bin/bash
set -e
# Check if the -it flag is provided
if [ -t 0 ] && [ -t 1 ]; then
echo "Running in interactive mode"
else
echo "Error: This container requires an interactive shell (-it flag)."
exit 1
fi
# Check if the volume directory is present
if [ ! -d "${SHARE_DIR}" ]; then
echo "Warning: Volume directory '${SHARE_DIR}' is missing."
echo "Please use the -v flag to specify a host directory."
echo "For example 'podman run -v /host/path:${SHARE_DIR}'"
echo "You will need to manually copy fuzzing inputs/outputs from/to the host"
fi
# Continue with the original command
exec "$@"

@ -1,7 +1,7 @@
# Shellcode Emulator Tests
These tests are used to validate basic bdshemu functionality. Each test consists of up to three files:
* The binary test file. The name format for this type of file is `name_32|64[_r0].test`. 32 indicates 32 bit test file, 64 indicates 64 bit test file, and r0 indicates kernel payload
* The binary test file. The name format for this type of file is `name_32|64[_r0]`. No extension must be provided; 32 indicates 32 bit test file, 64 indicates 64 bit test file, and r0 indicates kernel payload
* The output result file. Must be named the same as the binary test file, but with the extension .result
* Optional assembly file, used to generate the binary test file

Binary file not shown.

@ -5,175 +5,87 @@
import os
import sys
import glob
import shutil
from zipfile import ZipFile
from pathlib import Path
TEMP_PATH = "!temp"
total_tests = 0
failed_tests = 0
# A test file-name contains some indicators as to how the emulation should be done:
# - If '_16' is present in the name, emulation will be done on 16 bit
# - If '_32' is present in the name, emulation will be done on 32 bit
# - If '_64' is present in the name, emulation will be done on 64 bit
# - If '_r0' is present in the name, emulation will be done as kernel code
# A test case consists of minimum two files:
# - An '.test' file, containing the binary code to be emulated
# - An '.result' file, containing the emulation output
# A test is considered passed if the output produced during emulation is identical to the
# output containted in the '.result' file.
#
# test_dir
#
# Runs the tests inside the provided directory.
# Returns a tuplecontaining the total number of tests run and the number of failed tests.
#
def test_dir(dir, arch='x86'):
total_tests = 0
failed_tests = 0
def test_dir(dir):
global total_tests
global failed_tests
for f in glob.glob('%s\\*.test' % dir):
base, _ = os.path.splitext(f)
tst_file = f
res_file = base + '.result'
tmp_file = base + '.temp'
if 0 < tst_file.find('_16'):
mod = '-b16'
elif 0 < tst_file.find('_32'):
mod = '-b32'
else:
mod = '-b64'
if 0 < tst_file.find('_r0'):
mod += ' -k'
print(' * Running test case %s...' % tst_file)
os.system('disasm shemu %s -f %s >%s' % (mod, tst_file, tmp_file))
try:
res = open(res_file).read()
except:
print(' ! No result file provided for test %s!' % tst_file)
try:
tmp = open(tmp_file).read()
except:
print(' ! No result produced by test %s!' % tst_file)
total_tests += 1
if res != tmp:
print(' **** FAILED! ****')
failed_tests += 1
else:
print(' * Passed.')
# Cleanup.
os.remove(tmp_file)
os.remove(tst_file + "_decoded.bin")
return (total_tests, failed_tests)
#
# regenerate
#
def regenerate(dir, arch='x86'):
for f in glob.glob('%s\\*.test' % dir):
base, _ = os.path.splitext(f)
tst_file = f
res_file = base + '.result'
if 0 < f.find('_16'):
mod = '-b16'
elif 0 < f.find('_32'):
mod = '-b32'
else:
mod = '-b64'
for f in glob.glob('%s\\*' % dir):
if -1 == f.find('.'):
if 0 < f.find('_16'):
mod = '-b16'
elif 0 < f.find('_32'):
mod = '-b32'
else:
mod = '-b64'
if 0 < f.find('_r0'):
mod += ' -k'
print(' * Running test case %s...' % f)
os.system('disasm shemu %s -f %s >%s.temp' % (mod, f, f))
try:
res = open('%s.result' % f).read()
except:
print(' ! No result file provided for test %s!' % f)
try:
tmp = open('%s.temp' % f).read()
except:
print(' ! No result produced by test %s!' % f)
if 0 < f.find('_r0'):
mod += ' -k'
total_tests += 1
if res != tmp:
print(' **** FAILED! ****')
failed_tests += 1
else:
print(' * Passed.')
print(' * Regenerating test case %s...' % tst_file)
os.system('disasm -exi shemu %s -f %s >%s' % (mod, tst_file, res_file))
for f in glob.glob('%s\\*_decoded.bin' % dir):
os.remove(f)
for f in glob.glob('%s\\*.temp' % dir):
os.remove(f)
# Cleanup.
os.remove(tst_file + "_decoded.bin")
#
# parse_dir_rec
#
def parse_dir_rec(dir, arch, handler):
for f in glob.glob(dir + "\\*"):
path, name = os.path.split(f)
if name in ['.', '..']:
continue
if os.path.isdir(f):
parse_dir_rec(f, arch, handler)
handler(f, arch)
#
# test_archive
#
def test_archive(filename, arch='x86'):
cleanup_files = []
# Run the x86 test.
print("Extracting test archive...")
with ZipFile(filename) as zf:
cleanup_files = zf.namelist()
zf.extractall(path=TEMP_PATH)
zf.close()
print("Running tests...")
total_tests, failed_tests = 0, 0
for dn in glob.glob(os.path.join(TEMP_PATH, "*")):
if not os.path.isdir(dn):
continue
print('Testing %s...' % dn)
cnt_tests, cnt_failed = test_dir(dn, arch)
total_tests += cnt_tests
failed_tests += cnt_failed
print("========================================================================")
print("Summary:")
print("Ran %d tests, %d failed" % (total_tests, failed_tests))
print("========================================================================")
print()
shutil.rmtree(TEMP_PATH)
def regenerate(dir):
for f in glob.glob('%s\\*' % dir):
if -1 == f.find('.'):
if 0 < f.find('_16'):
mod = '-b16'
elif 0 < f.find('_32'):
mod = '-b32'
else:
mod = '-b64'
if 0 < f.find('_r0'):
mod += ' -k'
print(' * Regenerating test case %s...' % f)
os.system('disasm -exi shemu %s -f %s >%s.result' % (mod, f, f))
for f in glob.glob('%s\\*_decoded.bin' % dir):
os.remove(f)
cleanup_files = []
if __name__ == "__main__":
# No arguments provided, auto-run all tests.
if len(sys.argv) == 1:
print("Running x86 tests...")
test_archive("x86\\bdshemu_test_x86.zip")
sys.exit(0)
print("Extracting test archive...\n")
with ZipFile('bdshemu_test.zip') as zf:
cleanup_files = zf.namelist()
zf.extractall()
print("Done!\n")
opt_dir = ""
opt_regen = False
opt_arch = 'x86'
for arg in sys.argv[1:]:
if os.path.isdir(arg):
print("Will test directory", arg)
opt_dir = arg
if arg == "regenerate":
print("Will regenerate tests...")
opt_regen = True
print("Identified architecture: ", opt_arch)
# Single directory test.
if not opt_dir:
print("A directory containing tests must be supplied!")
sys.exit(-1)
for dn in glob.glob("*"):
if not os.path.isdir(dn):
continue
print('Testing %s...' % dn)
test_dir(dn)
print("Ran %d tests, %d failed" % (total_tests, failed_tests))
if opt_regen:
parse_dir_rec(opt_dir, opt_arch, regenerate)
else:
parse_dir_rec(opt_dir, opt_arch, test_dir)
print("Cleaning up test files...\n")
for f in cleanup_files:
p = Path(os.getcwd()) / f
if p.is_file():
p.unlink()
print("Done!\n")

@ -15,7 +15,7 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#ifdef _MSC_VER
#if _MSC_VER
int nd_vsnprintf_s(char *buffer, size_t size, size_t count, const char *format, va_list argptr)
{
return vsnprintf(buffer, size, format, argptr);
@ -27,7 +27,7 @@ void * nd_memset(void *s, int c, size_t n)
}
#endif
void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, const char **build_date, const char **build_time)
void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, char **build_date, char **build_time)
{
NdGetVersion(major, minor, revision, build_date, build_time);
}

@ -7,7 +7,7 @@
#include "bddisasm.h"
void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, const char **build_date, const char **build_time);
void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, char **build_date, char **build_time);
NDSTATUS nd_decode(INSTRUX *__output_instr, const ND_UINT8 *code, ND_UINT8 def_code, ND_UINT8 def_data);
NDSTATUS nd_decode_ex(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_UINT8 def_code, ND_UINT8 def_data);
NDSTATUS nd_decode_ex2(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_UINT8 def_code, ND_UINT8 def_data,

@ -9,6 +9,13 @@
#include "pybddisasm.h"
#include "bddisasm.h"
#include "constants.h"
#include "cpuidflags.h"
#include "disasmstatus.h"
#include "disasmtypes.h"
#include "registers.h"
#include "version.h"
%}
%include "typemaps.i"
@ -158,10 +165,13 @@
%define __x86_64__
%enddef
%include "bddisasm.h"
%include "bdx86_constants.h"
%include "bdx86_cpuidflags.h"
%include "bddisasm_status.h"
%include "bddisasm_types.h"
%include "bdx86_registers.h"
%include "bdx86_core.h"
%include "constants.h"
%include "cpuidflags.h"
%include "disasmstatus.h"
%include "disasmtypes.h"
%include "registers.h"
%include "version.h"
%include "pybddisasm.h"

@ -12,7 +12,7 @@ from setuptools import find_packages, setup, Command, Extension, Distribution
from codecs import open
VERSION = (0, 3, 0)
LIBRARY_VERSION = (2, 1, 0)
LIBRARY_VERSION = (1, 38, 0)
DIR_INCLUDE = '../../inc'
here = os.path.abspath(os.path.dirname(__file__))
@ -25,6 +25,7 @@ __library_dirs = ['../../build', '../../bin/x64/Release']
__packages = ['pybddisasm']
__requires = ['setuptools']
class BinaryDistribution(Distribution):
def has_ext_modules(arg):
return True
@ -32,8 +33,10 @@ class BinaryDistribution(Distribution):
def is_pure(self):
return False
def __fn_validate_compatibility():
version_header = '%s/bddisasm_version.h' % (DIR_INCLUDE)
print(os.getcwd())
version_header = '%s/version.h' % (DIR_INCLUDE)
with open(version_header, 'r') as file:
data = file.read()
@ -59,9 +62,10 @@ def __fn_validate_compatibility():
if int(major) != LIBRARY_VERSION[0] or int(minor) != LIBRARY_VERSION[1] or int(revision) != LIBRARY_VERSION[2]:
print('error: The version of the library is not compatible with the pybddisasm!')
print('error: Library : %s.%s.%s - pybddisasm : %d.%d.%d' % (major, minor, revision, LIBRARY_VERSION[0],
LIBRARY_VERSION[1], LIBRARY_VERSION[2]))
LIBRARY_VERSION[1], LIBRARY_VERSION[2]))
sys.exit(1)
__fn_validate_compatibility()
with open('README.md', 'r', 'utf-8') as f:
@ -87,12 +91,11 @@ setup(
install_requires=__requires,
zip_safe=False,
classifiers=[
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'License :: OSI Approved :: Apache Software License',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: Linux'

@ -4,6 +4,3 @@ members = [
"bddisasm-sys",
"bddisasm",
]
[workspace.package]
version = "0.2.3"

@ -1,6 +1,6 @@
[package]
name = "bddisasm-sys"
version.workspace = true
version = "0.4.0"
authors = ["Cristi Anichitei <ianichitei@bitdefender.com>"]
edition = "2018"
links = "bddisasm"
@ -23,5 +23,5 @@ path = "src/lib.rs"
cty = "0.2.2"
[build-dependencies]
bindgen = "0.62.0"
bindgen = "0.59.1"
cc = "1.0.70"

@ -9,10 +9,10 @@ fn main() {
println!("cargo:rerun-if-changed=csrc");
cc::Build::new()
.file("csrc/bddisasm/bddisasm_crt.c")
.file("csrc/bddisasm/bdx86_decoder.c")
.file("csrc/bddisasm/bdx86_formatter.c")
.file("csrc/bddisasm/bdx86_helpers.c")
.file("csrc/bddisasm/bddisasm.c")
.file("csrc/bddisasm/bdformat.c")
.file("csrc/bddisasm/bdhelpers.c")
.file("csrc/bddisasm/crt.c")
.include("csrc/bddisasm/include")
.include("csrc/inc")
.define("BDDISASM_HAS_VSNPRINTF", Some("1"))

@ -30,8 +30,8 @@ mod tests {
let mut major: u32 = 0;
let mut minor: u32 = 0;
let mut revision: u32 = 0;
let mut build_date: *const c_char = std::ptr::null();
let mut build_time: *const c_char = std::ptr::null();
let mut build_date: *mut c_char = std::ptr::null_mut();
let mut build_time: *mut c_char = std::ptr::null_mut();
unsafe {
NdGetVersion(
@ -53,7 +53,7 @@ mod tests {
// There are no other asserts in this test. Enforcing a known minor version is not worth it, we mainly want to
// see that `NdGetVersion` works.
assert_eq!(major, 2);
assert_eq!(major, 1);
}
fn do_decode(code: &[u8]) -> (INSTRUX, NDSTATUS) {
@ -79,7 +79,10 @@ mod tests {
let (instrux, status) = do_decode(&code);
assert_eq!(status, 0, "Failed to decode instruction {:#x?}", code);
assert_eq!(instrux.Instruction, _ND_INS_CLASS::ND_INS_NOP);
assert_eq!(
unsafe { instrux.__bindgen_anon_2.Instruction },
_ND_INS_CLASS::ND_INS_NOP
);
}
#[test]

@ -2,13 +2,19 @@
## 0.3.1
### Removed
### Added
- support for new Intel ISA, per Intel Architecture Instruction Set Extensions and Future Features document #319433-049 (June 2023): AVX-NNI-INT16, SHA512, SM3, SM4, TSE.
### Changed
- `Mnemonic`, `IsaSet`, and `Category` use all caps for the enum variants
## 0.3.0
### Fixed
- the `ExceptionClass` enum
- `sse_cond`, `has_mvex`, `has_drex`, `has_imm3`, `immediate3`, `sign_disp`, `imm3_length`, `imm3_offset`, `bhint` from `DecodedInstruction`
- multiple variants from `Category`, `IsaSet`, `Mnemonic` in accordance with the changes in `bddisasm`
- `raw_size`, `decorator` from `Operand`
- the `Operand` struct
- #84: handle 0 sizes in `OpSize::from_raw`
## 0.2.1

@ -1,6 +1,6 @@
[package]
name = "bddisasm"
version.workspace = true
version = "0.3.0"
authors = ["Cristi Anichitei <ianichitei@bitdefender.com>"]
edition = "2018"
license = "Apache-2.0"
@ -14,7 +14,7 @@ categories = ["api-bindings", "hardware-support"]
keywords = ["disassembler", "decoder", "x86", "amd64", "x86_64"]
[dependencies]
bddisasm-sys = { version = "0.2.3", path = "../bddisasm-sys" }
bddisasm-sys = { version = "0.4.0", path = "../bddisasm-sys" }
[features]
std = []
@ -23,5 +23,5 @@ std = []
all-features = true
[dev-dependencies]
anyhow = "1.0.0"
anyhow = "1.0"
clap = "2.34.0"

@ -29,7 +29,6 @@
// TODO: maybe use something like the `bitflags` crate and have all these as flags?
/// Privilege levels (rings) in which an instruction is supported.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct PrivilegeLevel {
/// Instruction is valid in ring 0.
@ -46,7 +45,6 @@ pub struct PrivilegeLevel {
}
/// Operating modes in which an instruction is supported.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct OperatingMode {
/// The instruction is valid in real mode.
@ -66,7 +64,6 @@ pub struct OperatingMode {
}
/// Special modes - these may be active inside other modes (example: `TSX` in `Long mode`).
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct SpecialModes {
/// The instruction is valid in System Management Mode.
@ -89,7 +86,6 @@ pub struct SpecialModes {
}
/// VMX mode - they engulf all the other modes.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct VmxMode {
/// The instruction is valid in VMX root mode.

@ -7,7 +7,7 @@
//!
//! # Notes
//!
//! All error codes that can be returned by `bddisasm-sys` are encapsulated in the [`DecodeError`] enum.
//! All error codes that can be returned by `bddisasm-sys` are encapsulated in the [`DecodeError`](DecodeError) enum.
//! However, some of these are unlikely to be encountered when using this crate (for example,
//! [`BufferOverflow`](DecodeError::BufferOverflow)) which indicates that a buffer passed to the `bddisasm` C library is
//! not large enough.
@ -117,9 +117,6 @@ pub enum DecodeError {
/// Not enough space is available.
BufferOverflow,
/// EVEX payload byte 3 is invalid.
InvalidEvexByte3,
/// Internal library error.
InternalError(u64),
}
@ -184,9 +181,6 @@ impl fmt::Display for DecodeError {
DecodeError::BufferOverflow => {
write!(f, "not enough space is available to format instruction")
}
DecodeError::InvalidEvexByte3 => {
write!(f, "EVEX payload byte 3 is invalid.")
}
DecodeError::InternalError(e) => write!(f, "internal error: {}", e),
}
}
@ -238,7 +232,6 @@ pub(crate) fn status_to_error(status: ffi::NDSTATUS) -> Result<(), DecodeError>
ffi::ND_STATUS_INVALID_PARAMETER => Err(DecodeError::InvalidParameter),
ffi::ND_STATUS_INVALID_INSTRUX => Err(DecodeError::InvalidInstrux),
ffi::ND_STATUS_BUFFER_OVERFLOW => Err(DecodeError::BufferOverflow),
ffi::ND_STATUS_INVALID_EVEX_BYTE3 => Err(DecodeError::InvalidEvexByte3),
ffi::ND_STATUS_INTERNAL_ERROR => Err(DecodeError::InternalError(0)),
_ => panic!("Unexpected status: {:#x}", status),
}

File diff suppressed because it is too large Load Diff

@ -20,11 +20,10 @@ impl<'a> Decoder<'a> {
///
/// # Arguments
///
/// * `code` - An [`u8`] slice that holds the code to be decoded.
/// * `code` - An [u8](u8) slice that holds the code to be decoded.
/// * `mode` - The mode in which to decode the instruction.
/// * `ip` - The instruction pointer value to use when formatting the decoded instruction. Does not affect the
/// decoding process in any way.
#[must_use]
pub fn new(code: &'a [u8], mode: DecodeMode, ip: u64) -> Self {
Self {
code,
@ -83,12 +82,15 @@ impl<'a> Decoder<'a> {
} else {
let result =
DecodedInstruction::decode_with_ip(&self.code[self.offset..], self.mode, self.ip);
if let Ok(ins) = result {
self.offset += ins.length();
self.ip += ins.length() as u64;
} else {
self.offset += 1;
self.ip += 1;
match result {
Ok(ins) => {
self.offset += ins.length() as usize;
self.ip += ins.length() as u64;
}
Err(_) => {
self.offset += 1;
self.ip += 1;
}
};
Some(result)
@ -97,7 +99,7 @@ impl<'a> Decoder<'a> {
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`] it
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// will also return the offset from which decoding was attempted, as well as the corresponding instruction pointer.
///
/// # Examples
@ -132,7 +134,7 @@ impl<'a> Decoder<'a> {
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`] it
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// will also return the offset from which decoding was attempted.
///
/// # Examples
@ -166,7 +168,7 @@ impl<'a> Decoder<'a> {
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`] it
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// will also return the corresponding instruction pointer.
///
/// # Examples

@ -4,8 +4,6 @@
*/
//! Offers information about how an instructions accesses the FPU status registers.
#![allow(clippy::module_name_repetitions)]
use super::decode_error::DecodeError;
/// The mode in which a FPU status flag is accessed.

@ -15,7 +15,6 @@ pub enum Category {
AES,
AESKL,
AMX,
APX,
ARITH,
AVX,
AVX2,
@ -73,6 +72,7 @@ pub enum Category {
MOVDIRI,
MPX,
NOP,
PADLOCK,
PCLMULQDQ,
PCONFIG,
POP,
@ -108,7 +108,6 @@ pub enum Category {
UINTR,
UNCOND_BR,
UNKNOWN,
USER_MSR,
VAES,
VFMA,
VFMAPS,
@ -130,7 +129,6 @@ pub enum Category {
impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_CATEGORY) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_TYPE::ND_CAT_INVALID => Err(DecodeError::InternalError(value as u64)),
@ -138,7 +136,6 @@ impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
ffi::_ND_INS_TYPE::ND_CAT_AES => Ok(Category::AES),
ffi::_ND_INS_TYPE::ND_CAT_AESKL => Ok(Category::AESKL),
ffi::_ND_INS_TYPE::ND_CAT_AMX => Ok(Category::AMX),
ffi::_ND_INS_TYPE::ND_CAT_APX => Ok(Category::APX),
ffi::_ND_INS_TYPE::ND_CAT_ARITH => Ok(Category::ARITH),
ffi::_ND_INS_TYPE::ND_CAT_AVX => Ok(Category::AVX),
ffi::_ND_INS_TYPE::ND_CAT_AVX2 => Ok(Category::AVX2),
@ -196,6 +193,7 @@ impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
ffi::_ND_INS_TYPE::ND_CAT_MOVDIRI => Ok(Category::MOVDIRI),
ffi::_ND_INS_TYPE::ND_CAT_MPX => Ok(Category::MPX),
ffi::_ND_INS_TYPE::ND_CAT_NOP => Ok(Category::NOP),
ffi::_ND_INS_TYPE::ND_CAT_PADLOCK => Ok(Category::PADLOCK),
ffi::_ND_INS_TYPE::ND_CAT_PCLMULQDQ => Ok(Category::PCLMULQDQ),
ffi::_ND_INS_TYPE::ND_CAT_PCONFIG => Ok(Category::PCONFIG),
ffi::_ND_INS_TYPE::ND_CAT_POP => Ok(Category::POP),
@ -231,7 +229,6 @@ impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
ffi::_ND_INS_TYPE::ND_CAT_UINTR => Ok(Category::UINTR),
ffi::_ND_INS_TYPE::ND_CAT_UNCOND_BR => Ok(Category::UNCOND_BR),
ffi::_ND_INS_TYPE::ND_CAT_UNKNOWN => Ok(Category::UNKNOWN),
ffi::_ND_INS_TYPE::ND_CAT_USER_MSR => Ok(Category::USER_MSR),
ffi::_ND_INS_TYPE::ND_CAT_VAES => Ok(Category::VAES),
ffi::_ND_INS_TYPE::ND_CAT_VFMA => Ok(Category::VFMA),
ffi::_ND_INS_TYPE::ND_CAT_VFMAPS => Ok(Category::VFMAPS),

@ -20,7 +20,6 @@ pub enum IsaSet {
AMXFP16,
AMXINT8,
AMXTILE,
APX_F,
AVX,
AVX2,
AVX2GATHER,
@ -57,6 +56,8 @@ pub enum IsaSet {
CLZERO,
CMPCCXADD,
CMPXCHG16B,
CYRIX,
CYRIX_SMM,
ENQCMD,
F16C,
FMA,
@ -131,7 +132,6 @@ pub enum IsaSet {
UD,
UINTR,
UNKNOWN,
USER_MSR,
VAES,
VPCLMULQDQ,
VTX,
@ -149,7 +149,6 @@ pub enum IsaSet {
impl TryFrom<ffi::ND_INS_SET> for IsaSet {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_SET) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_SET::ND_SET_INVALID => Err(DecodeError::InternalError(value as u64)),
@ -162,7 +161,6 @@ impl TryFrom<ffi::ND_INS_SET> for IsaSet {
ffi::_ND_INS_SET::ND_SET_AMXFP16 => Ok(IsaSet::AMXFP16),
ffi::_ND_INS_SET::ND_SET_AMXINT8 => Ok(IsaSet::AMXINT8),
ffi::_ND_INS_SET::ND_SET_AMXTILE => Ok(IsaSet::AMXTILE),
ffi::_ND_INS_SET::ND_SET_APX_F => Ok(IsaSet::APX_F),
ffi::_ND_INS_SET::ND_SET_AVX => Ok(IsaSet::AVX),
ffi::_ND_INS_SET::ND_SET_AVX2 => Ok(IsaSet::AVX2),
ffi::_ND_INS_SET::ND_SET_AVX2GATHER => Ok(IsaSet::AVX2GATHER),
@ -199,6 +197,8 @@ impl TryFrom<ffi::ND_INS_SET> for IsaSet {
ffi::_ND_INS_SET::ND_SET_CLZERO => Ok(IsaSet::CLZERO),
ffi::_ND_INS_SET::ND_SET_CMPCCXADD => Ok(IsaSet::CMPCCXADD),
ffi::_ND_INS_SET::ND_SET_CMPXCHG16B => Ok(IsaSet::CMPXCHG16B),
ffi::_ND_INS_SET::ND_SET_CYRIX => Ok(IsaSet::CYRIX),
ffi::_ND_INS_SET::ND_SET_CYRIX_SMM => Ok(IsaSet::CYRIX_SMM),
ffi::_ND_INS_SET::ND_SET_ENQCMD => Ok(IsaSet::ENQCMD),
ffi::_ND_INS_SET::ND_SET_F16C => Ok(IsaSet::F16C),
ffi::_ND_INS_SET::ND_SET_FMA => Ok(IsaSet::FMA),
@ -273,7 +273,6 @@ impl TryFrom<ffi::ND_INS_SET> for IsaSet {
ffi::_ND_INS_SET::ND_SET_UD => Ok(IsaSet::UD),
ffi::_ND_INS_SET::ND_SET_UINTR => Ok(IsaSet::UINTR),
ffi::_ND_INS_SET::ND_SET_UNKNOWN => Ok(IsaSet::UNKNOWN),
ffi::_ND_INS_SET::ND_SET_USER_MSR => Ok(IsaSet::USER_MSR),
ffi::_ND_INS_SET::ND_SET_VAES => Ok(IsaSet::VAES),
ffi::_ND_INS_SET::ND_SET_VPCLMULQDQ => Ok(IsaSet::VPCLMULQDQ),
ffi::_ND_INS_SET::ND_SET_VTX => Ok(IsaSet::VTX),

@ -22,7 +22,7 @@
//!
//! ```toml
//! [dependencies]
//! bddisasm = "0.2"
//! bddisasm = "0.1.0"
//! ```
//!
//! # Examples
@ -47,7 +47,7 @@
//!
//! ## Decoding multiple instructions
//!
//! Use [`Decoder`] to decode multiple instructions from a chunk of code.
//! Use [`Decoder`](crate::decoder::Decoder) to decode multiple instructions from a chunk of code.
//!
//! ```
//! use bddisasm::{Decoder, DecodeMode};
@ -120,7 +120,7 @@
//!
//! ## Working with instruction operands
//!
//! Instruction operands can be analyzed using the [`operand`] module. Rich informaion is offered for
//! Instruction operands can be analyzed using the [operand](crate::operand) module. Rich informaion is offered for
//! each type of operand. Bellow is a minimal example that looks at a memory operand.
//!
//! ```
@ -190,7 +190,6 @@
//!
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
#![allow(clippy::if_not_else)]
pub extern crate bddisasm_sys as ffi;

@ -41,6 +41,7 @@ pub enum Mnemonic {
AESENCWIDE256KL,
AESIMC,
AESKEYGENASSIST,
ALTINST,
AND,
ANDN,
ANDNPD,
@ -86,10 +87,8 @@ pub enum Mnemonic {
CALLNI,
CALLNR,
CBW,
CCMP,
CDQ,
CDQE,
CFCMOV,
CLAC,
CLC,
CLD,
@ -135,9 +134,10 @@ pub enum Mnemonic {
COMISD,
COMISS,
CPUID,
CPU_READ,
CPU_WRITE,
CQO,
CRC32,
CTEST,
CVTDQ2PD,
CVTDQ2PS,
CVTPD2DQ,
@ -171,6 +171,7 @@ pub enum Mnemonic {
DIVPS,
DIVSD,
DIVSS,
DMINT,
DPPD,
DPPS,
EMMS,
@ -314,7 +315,6 @@ pub enum Mnemonic {
INVPCID,
INVVPID,
IRET,
JMPABS,
JMPE,
JMPFD,
JMPFI,
@ -382,6 +382,7 @@ pub enum Mnemonic {
MINSS,
MONITOR,
MONITORX,
MONTMUL,
MOV,
MOVAPD,
MOVAPS,
@ -556,13 +557,10 @@ pub enum Mnemonic {
PMULLW,
PMULUDQ,
POP,
POP2,
POP2P,
POPA,
POPAD,
POPCNT,
POPF,
POPP,
POR,
PREFETCH,
PREFETCHE,
@ -615,12 +613,9 @@ pub enum Mnemonic {
PUNPCKLQDQ,
PUNPCKLWD,
PUSH,
PUSH2,
PUSH2P,
PUSHA,
PUSHAD,
PUSHF,
PUSHP,
PVALIDATE,
PXOR,
RCL,
@ -637,6 +632,7 @@ pub enum Mnemonic {
RDPRU,
RDRAND,
RDSEED,
RDSHR,
RDTSC,
RDTSCP,
RETF,
@ -651,11 +647,14 @@ pub enum Mnemonic {
ROUNDPS,
ROUNDSD,
ROUNDSS,
RSDC,
RSLDT,
RSM,
RSQRTPS,
RSQRTSS,
RSSSP,
RSTORSSP,
RSTS,
SAHF,
SAL,
SALC,
@ -692,6 +691,7 @@ pub enum Mnemonic {
SKINIT,
SLDT,
SLWPCB,
SMINT,
SMSW,
SPFLT,
SQRTPD,
@ -713,6 +713,9 @@ pub enum Mnemonic {
SUBPS,
SUBSD,
SUBSS,
SVDC,
SVLDT,
SVTS,
SWAPGS,
SYSCALL,
SYSENTER,
@ -751,8 +754,6 @@ pub enum Mnemonic {
UNPCKHPS,
UNPCKLPD,
UNPCKLPS,
URDMSR,
UWRMSR,
V4FMADDPS,
V4FMADDSS,
V4FNMADDPS,
@ -1620,12 +1621,18 @@ pub enum Mnemonic {
WRMSRLIST,
WRMSRNS,
WRPKRU,
WRSHR,
WRSS,
WRUSS,
XABORT,
XADD,
XBEGIN,
XCHG,
XCRYPTCBC,
XCRYPTCFB,
XCRYPTCTR,
XCRYPTECB,
XCRYPTOFB,
XEND,
XGETBV,
XLATB,
@ -1640,6 +1647,9 @@ pub enum Mnemonic {
XSAVEOPT,
XSAVES,
XSETBV,
XSHA1,
XSHA256,
XSTORE,
XSUSLDTRK,
XTEST,
}
@ -1648,7 +1658,6 @@ pub enum Mnemonic {
impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_CLASS) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_CLASS::ND_INS_INVALID => Err(DecodeError::InternalError(value as u64)),
@ -1682,6 +1691,7 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_AESENCWIDE256KL => Ok(Mnemonic::AESENCWIDE256KL),
ffi::_ND_INS_CLASS::ND_INS_AESIMC => Ok(Mnemonic::AESIMC),
ffi::_ND_INS_CLASS::ND_INS_AESKEYGENASSIST => Ok(Mnemonic::AESKEYGENASSIST),
ffi::_ND_INS_CLASS::ND_INS_ALTINST => Ok(Mnemonic::ALTINST),
ffi::_ND_INS_CLASS::ND_INS_AND => Ok(Mnemonic::AND),
ffi::_ND_INS_CLASS::ND_INS_ANDN => Ok(Mnemonic::ANDN),
ffi::_ND_INS_CLASS::ND_INS_ANDNPD => Ok(Mnemonic::ANDNPD),
@ -1727,10 +1737,8 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_CALLNI => Ok(Mnemonic::CALLNI),
ffi::_ND_INS_CLASS::ND_INS_CALLNR => Ok(Mnemonic::CALLNR),
ffi::_ND_INS_CLASS::ND_INS_CBW => Ok(Mnemonic::CBW),
ffi::_ND_INS_CLASS::ND_INS_CCMP => Ok(Mnemonic::CCMP),
ffi::_ND_INS_CLASS::ND_INS_CDQ => Ok(Mnemonic::CDQ),
ffi::_ND_INS_CLASS::ND_INS_CDQE => Ok(Mnemonic::CDQE),
ffi::_ND_INS_CLASS::ND_INS_CFCMOV => Ok(Mnemonic::CFCMOV),
ffi::_ND_INS_CLASS::ND_INS_CLAC => Ok(Mnemonic::CLAC),
ffi::_ND_INS_CLASS::ND_INS_CLC => Ok(Mnemonic::CLC),
ffi::_ND_INS_CLASS::ND_INS_CLD => Ok(Mnemonic::CLD),
@ -1776,9 +1784,10 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_COMISD => Ok(Mnemonic::COMISD),
ffi::_ND_INS_CLASS::ND_INS_COMISS => Ok(Mnemonic::COMISS),
ffi::_ND_INS_CLASS::ND_INS_CPUID => Ok(Mnemonic::CPUID),
ffi::_ND_INS_CLASS::ND_INS_CPU_READ => Ok(Mnemonic::CPU_READ),
ffi::_ND_INS_CLASS::ND_INS_CPU_WRITE => Ok(Mnemonic::CPU_WRITE),
ffi::_ND_INS_CLASS::ND_INS_CQO => Ok(Mnemonic::CQO),
ffi::_ND_INS_CLASS::ND_INS_CRC32 => Ok(Mnemonic::CRC32),
ffi::_ND_INS_CLASS::ND_INS_CTEST => Ok(Mnemonic::CTEST),
ffi::_ND_INS_CLASS::ND_INS_CVTDQ2PD => Ok(Mnemonic::CVTDQ2PD),
ffi::_ND_INS_CLASS::ND_INS_CVTDQ2PS => Ok(Mnemonic::CVTDQ2PS),
ffi::_ND_INS_CLASS::ND_INS_CVTPD2DQ => Ok(Mnemonic::CVTPD2DQ),
@ -1812,6 +1821,7 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_DIVPS => Ok(Mnemonic::DIVPS),
ffi::_ND_INS_CLASS::ND_INS_DIVSD => Ok(Mnemonic::DIVSD),
ffi::_ND_INS_CLASS::ND_INS_DIVSS => Ok(Mnemonic::DIVSS),
ffi::_ND_INS_CLASS::ND_INS_DMINT => Ok(Mnemonic::DMINT),
ffi::_ND_INS_CLASS::ND_INS_DPPD => Ok(Mnemonic::DPPD),
ffi::_ND_INS_CLASS::ND_INS_DPPS => Ok(Mnemonic::DPPS),
ffi::_ND_INS_CLASS::ND_INS_EMMS => Ok(Mnemonic::EMMS),
@ -1955,7 +1965,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_INVPCID => Ok(Mnemonic::INVPCID),
ffi::_ND_INS_CLASS::ND_INS_INVVPID => Ok(Mnemonic::INVVPID),
ffi::_ND_INS_CLASS::ND_INS_IRET => Ok(Mnemonic::IRET),
ffi::_ND_INS_CLASS::ND_INS_JMPABS => Ok(Mnemonic::JMPABS),
ffi::_ND_INS_CLASS::ND_INS_JMPE => Ok(Mnemonic::JMPE),
ffi::_ND_INS_CLASS::ND_INS_JMPFD => Ok(Mnemonic::JMPFD),
ffi::_ND_INS_CLASS::ND_INS_JMPFI => Ok(Mnemonic::JMPFI),
@ -2023,6 +2032,7 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_MINSS => Ok(Mnemonic::MINSS),
ffi::_ND_INS_CLASS::ND_INS_MONITOR => Ok(Mnemonic::MONITOR),
ffi::_ND_INS_CLASS::ND_INS_MONITORX => Ok(Mnemonic::MONITORX),
ffi::_ND_INS_CLASS::ND_INS_MONTMUL => Ok(Mnemonic::MONTMUL),
ffi::_ND_INS_CLASS::ND_INS_MOV => Ok(Mnemonic::MOV),
ffi::_ND_INS_CLASS::ND_INS_MOVAPD => Ok(Mnemonic::MOVAPD),
ffi::_ND_INS_CLASS::ND_INS_MOVAPS => Ok(Mnemonic::MOVAPS),
@ -2197,13 +2207,10 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_PMULLW => Ok(Mnemonic::PMULLW),
ffi::_ND_INS_CLASS::ND_INS_PMULUDQ => Ok(Mnemonic::PMULUDQ),
ffi::_ND_INS_CLASS::ND_INS_POP => Ok(Mnemonic::POP),
ffi::_ND_INS_CLASS::ND_INS_POP2 => Ok(Mnemonic::POP2),
ffi::_ND_INS_CLASS::ND_INS_POP2P => Ok(Mnemonic::POP2P),
ffi::_ND_INS_CLASS::ND_INS_POPA => Ok(Mnemonic::POPA),
ffi::_ND_INS_CLASS::ND_INS_POPAD => Ok(Mnemonic::POPAD),
ffi::_ND_INS_CLASS::ND_INS_POPCNT => Ok(Mnemonic::POPCNT),
ffi::_ND_INS_CLASS::ND_INS_POPF => Ok(Mnemonic::POPF),
ffi::_ND_INS_CLASS::ND_INS_POPP => Ok(Mnemonic::POPP),
ffi::_ND_INS_CLASS::ND_INS_POR => Ok(Mnemonic::POR),
ffi::_ND_INS_CLASS::ND_INS_PREFETCH => Ok(Mnemonic::PREFETCH),
ffi::_ND_INS_CLASS::ND_INS_PREFETCHE => Ok(Mnemonic::PREFETCHE),
@ -2256,12 +2263,9 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_PUNPCKLQDQ => Ok(Mnemonic::PUNPCKLQDQ),
ffi::_ND_INS_CLASS::ND_INS_PUNPCKLWD => Ok(Mnemonic::PUNPCKLWD),
ffi::_ND_INS_CLASS::ND_INS_PUSH => Ok(Mnemonic::PUSH),
ffi::_ND_INS_CLASS::ND_INS_PUSH2 => Ok(Mnemonic::PUSH2),
ffi::_ND_INS_CLASS::ND_INS_PUSH2P => Ok(Mnemonic::PUSH2P),
ffi::_ND_INS_CLASS::ND_INS_PUSHA => Ok(Mnemonic::PUSHA),
ffi::_ND_INS_CLASS::ND_INS_PUSHAD => Ok(Mnemonic::PUSHAD),
ffi::_ND_INS_CLASS::ND_INS_PUSHF => Ok(Mnemonic::PUSHF),
ffi::_ND_INS_CLASS::ND_INS_PUSHP => Ok(Mnemonic::PUSHP),
ffi::_ND_INS_CLASS::ND_INS_PVALIDATE => Ok(Mnemonic::PVALIDATE),
ffi::_ND_INS_CLASS::ND_INS_PXOR => Ok(Mnemonic::PXOR),
ffi::_ND_INS_CLASS::ND_INS_RCL => Ok(Mnemonic::RCL),
@ -2278,6 +2282,7 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_RDPRU => Ok(Mnemonic::RDPRU),
ffi::_ND_INS_CLASS::ND_INS_RDRAND => Ok(Mnemonic::RDRAND),
ffi::_ND_INS_CLASS::ND_INS_RDSEED => Ok(Mnemonic::RDSEED),
ffi::_ND_INS_CLASS::ND_INS_RDSHR => Ok(Mnemonic::RDSHR),
ffi::_ND_INS_CLASS::ND_INS_RDTSC => Ok(Mnemonic::RDTSC),
ffi::_ND_INS_CLASS::ND_INS_RDTSCP => Ok(Mnemonic::RDTSCP),
ffi::_ND_INS_CLASS::ND_INS_RETF => Ok(Mnemonic::RETF),
@ -2292,11 +2297,14 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_ROUNDPS => Ok(Mnemonic::ROUNDPS),
ffi::_ND_INS_CLASS::ND_INS_ROUNDSD => Ok(Mnemonic::ROUNDSD),
ffi::_ND_INS_CLASS::ND_INS_ROUNDSS => Ok(Mnemonic::ROUNDSS),
ffi::_ND_INS_CLASS::ND_INS_RSDC => Ok(Mnemonic::RSDC),
ffi::_ND_INS_CLASS::ND_INS_RSLDT => Ok(Mnemonic::RSLDT),
ffi::_ND_INS_CLASS::ND_INS_RSM => Ok(Mnemonic::RSM),
ffi::_ND_INS_CLASS::ND_INS_RSQRTPS => Ok(Mnemonic::RSQRTPS),
ffi::_ND_INS_CLASS::ND_INS_RSQRTSS => Ok(Mnemonic::RSQRTSS),
ffi::_ND_INS_CLASS::ND_INS_RSSSP => Ok(Mnemonic::RSSSP),
ffi::_ND_INS_CLASS::ND_INS_RSTORSSP => Ok(Mnemonic::RSTORSSP),
ffi::_ND_INS_CLASS::ND_INS_RSTS => Ok(Mnemonic::RSTS),
ffi::_ND_INS_CLASS::ND_INS_SAHF => Ok(Mnemonic::SAHF),
ffi::_ND_INS_CLASS::ND_INS_SAL => Ok(Mnemonic::SAL),
ffi::_ND_INS_CLASS::ND_INS_SALC => Ok(Mnemonic::SALC),
@ -2333,6 +2341,7 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_SKINIT => Ok(Mnemonic::SKINIT),
ffi::_ND_INS_CLASS::ND_INS_SLDT => Ok(Mnemonic::SLDT),
ffi::_ND_INS_CLASS::ND_INS_SLWPCB => Ok(Mnemonic::SLWPCB),
ffi::_ND_INS_CLASS::ND_INS_SMINT => Ok(Mnemonic::SMINT),
ffi::_ND_INS_CLASS::ND_INS_SMSW => Ok(Mnemonic::SMSW),
ffi::_ND_INS_CLASS::ND_INS_SPFLT => Ok(Mnemonic::SPFLT),
ffi::_ND_INS_CLASS::ND_INS_SQRTPD => Ok(Mnemonic::SQRTPD),
@ -2354,6 +2363,9 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_SUBPS => Ok(Mnemonic::SUBPS),
ffi::_ND_INS_CLASS::ND_INS_SUBSD => Ok(Mnemonic::SUBSD),
ffi::_ND_INS_CLASS::ND_INS_SUBSS => Ok(Mnemonic::SUBSS),
ffi::_ND_INS_CLASS::ND_INS_SVDC => Ok(Mnemonic::SVDC),
ffi::_ND_INS_CLASS::ND_INS_SVLDT => Ok(Mnemonic::SVLDT),
ffi::_ND_INS_CLASS::ND_INS_SVTS => Ok(Mnemonic::SVTS),
ffi::_ND_INS_CLASS::ND_INS_SWAPGS => Ok(Mnemonic::SWAPGS),
ffi::_ND_INS_CLASS::ND_INS_SYSCALL => Ok(Mnemonic::SYSCALL),
ffi::_ND_INS_CLASS::ND_INS_SYSENTER => Ok(Mnemonic::SYSENTER),
@ -2392,8 +2404,6 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_UNPCKHPS => Ok(Mnemonic::UNPCKHPS),
ffi::_ND_INS_CLASS::ND_INS_UNPCKLPD => Ok(Mnemonic::UNPCKLPD),
ffi::_ND_INS_CLASS::ND_INS_UNPCKLPS => Ok(Mnemonic::UNPCKLPS),
ffi::_ND_INS_CLASS::ND_INS_URDMSR => Ok(Mnemonic::URDMSR),
ffi::_ND_INS_CLASS::ND_INS_UWRMSR => Ok(Mnemonic::UWRMSR),
ffi::_ND_INS_CLASS::ND_INS_V4FMADDPS => Ok(Mnemonic::V4FMADDPS),
ffi::_ND_INS_CLASS::ND_INS_V4FMADDSS => Ok(Mnemonic::V4FMADDSS),
ffi::_ND_INS_CLASS::ND_INS_V4FNMADDPS => Ok(Mnemonic::V4FNMADDPS),
@ -3261,12 +3271,18 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_WRMSRLIST => Ok(Mnemonic::WRMSRLIST),
ffi::_ND_INS_CLASS::ND_INS_WRMSRNS => Ok(Mnemonic::WRMSRNS),
ffi::_ND_INS_CLASS::ND_INS_WRPKRU => Ok(Mnemonic::WRPKRU),
ffi::_ND_INS_CLASS::ND_INS_WRSHR => Ok(Mnemonic::WRSHR),
ffi::_ND_INS_CLASS::ND_INS_WRSS => Ok(Mnemonic::WRSS),
ffi::_ND_INS_CLASS::ND_INS_WRUSS => Ok(Mnemonic::WRUSS),
ffi::_ND_INS_CLASS::ND_INS_XABORT => Ok(Mnemonic::XABORT),
ffi::_ND_INS_CLASS::ND_INS_XADD => Ok(Mnemonic::XADD),
ffi::_ND_INS_CLASS::ND_INS_XBEGIN => Ok(Mnemonic::XBEGIN),
ffi::_ND_INS_CLASS::ND_INS_XCHG => Ok(Mnemonic::XCHG),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTCBC => Ok(Mnemonic::XCRYPTCBC),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTCFB => Ok(Mnemonic::XCRYPTCFB),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTCTR => Ok(Mnemonic::XCRYPTCTR),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTECB => Ok(Mnemonic::XCRYPTECB),
ffi::_ND_INS_CLASS::ND_INS_XCRYPTOFB => Ok(Mnemonic::XCRYPTOFB),
ffi::_ND_INS_CLASS::ND_INS_XEND => Ok(Mnemonic::XEND),
ffi::_ND_INS_CLASS::ND_INS_XGETBV => Ok(Mnemonic::XGETBV),
ffi::_ND_INS_CLASS::ND_INS_XLATB => Ok(Mnemonic::XLATB),
@ -3281,6 +3297,9 @@ impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
ffi::_ND_INS_CLASS::ND_INS_XSAVEOPT => Ok(Mnemonic::XSAVEOPT),
ffi::_ND_INS_CLASS::ND_INS_XSAVES => Ok(Mnemonic::XSAVES),
ffi::_ND_INS_CLASS::ND_INS_XSETBV => Ok(Mnemonic::XSETBV),
ffi::_ND_INS_CLASS::ND_INS_XSHA1 => Ok(Mnemonic::XSHA1),
ffi::_ND_INS_CLASS::ND_INS_XSHA256 => Ok(Mnemonic::XSHA256),
ffi::_ND_INS_CLASS::ND_INS_XSTORE => Ok(Mnemonic::XSTORE),
ffi::_ND_INS_CLASS::ND_INS_XSUSLDTRK => Ok(Mnemonic::XSUSLDTRK),
ffi::_ND_INS_CLASS::ND_INS_XTEST => Ok(Mnemonic::XTEST),
}

@ -29,6 +29,10 @@ impl OpAddr {
offset: raw.Offset,
}
}
pub(crate) fn new(base_seg: u16, offset: u64) -> Self {
Self { base_seg, offset }
}
}
/// The type of a register.
@ -184,7 +188,7 @@ pub struct OpReg {
///
/// # Remarks
///
/// If [kind](OpReg::kind) is [`OpRegType::Gpr`], the high and low part of 16-bit registers will have
/// If [kind](OpReg::kind) is [OpRegType::Gpr](OpRegType::Gpr), the high and low part of 16-bit registers will have
/// the same index (for example, `AH` and `AL`). To differentiate between them use [is_high8](OpReg::is_high8).
pub index: usize,
@ -219,7 +223,7 @@ impl OpReg {
kind,
size: raw.Size,
index,
count: raw.Count as u32,
count: raw.Count,
is_high8,
is_block: raw.IsBlock() != 0,
})
@ -275,7 +279,6 @@ impl ShadowStackAccess {
}
/// Describes a memory operand.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct OpMem {
/// `true` if the memory operand is a broadcast operand.
@ -350,23 +353,19 @@ pub struct OpMem {
impl OpMem {
pub(crate) fn from_raw(raw: ffi::ND_OPDESC_MEMORY) -> Result<Self, DecodeError> {
let seg = if raw.HasSeg() != 0 {
Some(raw.Seg())
Some(raw.Seg)
} else {
None
};
let (base, base_size) = if raw.HasBase() != 0 {
(Some(raw.Base()), Some(raw.BaseSize as u32))
(Some(raw.Base), Some(raw.BaseSize))
} else {
(None, None)
};
let (index, index_size, scale) = if raw.HasIndex() != 0 {
(
Some(raw.Index),
Some(raw.IndexSize as u32),
Some(raw.Scale()),
)
(Some(raw.Index), Some(raw.IndexSize), Some(raw.Scale))
} else {
(None, None, None)
};
@ -386,10 +385,10 @@ impl OpMem {
let (vsib, index_size) = if raw.IsVsib() != 0 {
(
Some(Vsib {
vsib_element_size: unsafe { raw.__bindgen_anon_1.Vsib.ElemSize },
vsib_element_count: unsafe { raw.__bindgen_anon_1.Vsib.ElemCount },
vsib_element_size: raw.Vsib.ElemSize,
vsib_element_count: raw.Vsib.ElemCount,
}),
Some(unsafe { raw.__bindgen_anon_1.Vsib.IndexSize.into() }),
Some(raw.Vsib.IndexSize.into()),
)
} else {
(None, index_size)
@ -461,9 +460,7 @@ impl Default for OpInfo {
}
impl OpInfo {
/// Returns the associated [`OpReg`] for register operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
/// Returns the associated [OpReg](OpReg) for register operands. Returns [`None`] otherwise.
pub fn as_reg(&self) -> Option<&OpReg> {
if let OpInfo::Reg(o) = self {
Some(o)
@ -472,9 +469,7 @@ impl OpInfo {
}
}
/// Returns the associated [`OpMem`] for memory operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
/// Returns the associated [OpMem](OpMem) for memory operands. Returns [`None`] otherwise.
pub fn as_mem(&self) -> Option<&OpMem> {
if let OpInfo::Mem(o) = self {
Some(o)
@ -484,8 +479,6 @@ impl OpInfo {
}
/// Returns the associated immediate value for immediate operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_imm(&self) -> Option<u64> {
if let OpInfo::Imm(o) = self {
Some(*o)
@ -494,9 +487,7 @@ impl OpInfo {
}
}
/// Returns the associated [`OpAddr`] for absolute address operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
/// Returns the associated [OpAddr](OpAddr) for absolute address operands. Returns [`None`] otherwise.
pub fn as_addr(&self) -> Option<&OpAddr> {
if let OpInfo::Addr(o) = self {
Some(o)
@ -506,8 +497,6 @@ impl OpInfo {
}
/// Returns the associated constant value for constant operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_const(&self) -> Option<u64> {
if let OpInfo::Const(o) = self {
Some(*o)
@ -517,8 +506,6 @@ impl OpInfo {
}
/// Returns `Some` for bank operands. Returns [`None`] otherwise.
#[inline]
#[must_use]
pub fn as_bank(&self) -> Option<()> {
if let OpInfo::Bank = self {
Some(())
@ -528,43 +515,31 @@ impl OpInfo {
}
/// Returns `true` for register operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_reg(&self) -> bool {
self.as_reg().is_some()
}
/// Returns `true` for memory operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_mem(&self) -> bool {
self.as_mem().is_some()
}
/// Returns `true` for immediate operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_imm(&self) -> bool {
self.as_imm().is_some()
}
/// Returns `true` for absolute address operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_addr(&self) -> bool {
self.as_addr().is_some()
}
/// Returns `true` for constant operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_const(&self) -> bool {
self.as_const().is_some()
}
/// Returns `true` for bank operands. Returns `false` otherwise.
#[inline]
#[must_use]
pub fn is_bank(&self) -> bool {
self.as_bank().is_some()
}
@ -573,26 +548,25 @@ impl OpInfo {
#[doc(hidden)]
impl OpInfo {
pub(crate) fn from_raw(raw: ffi::ND_OPERAND) -> Result<Self, DecodeError> {
let typ = raw.Type() as i32;
if typ == ffi::_ND_OPERAND_TYPE::ND_OP_NOT_PRESENT as i32 {
Ok(OpInfo::None)
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_REG as i32 {
Ok(OpInfo::Reg(OpReg::from_raw(unsafe { raw.Info.Register })?))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_MEM as i32 {
Ok(OpInfo::Mem(OpMem::from_raw(unsafe { raw.Info.Memory })?))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_IMM as i32 {
Ok(OpInfo::Imm(unsafe { raw.Info.Immediate }.Imm))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_OFFS as i32 {
Ok(OpInfo::Offs(unsafe { raw.Info.RelativeOffset }.Rel))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_ADDR as i32 {
Ok(OpInfo::Addr(OpAddr::from_raw(unsafe { raw.Info.Address })))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_CONST as i32 {
Ok(OpInfo::Const(unsafe { raw.Info.Constant }.Const))
} else if typ == ffi::_ND_OPERAND_TYPE::ND_OP_BANK as i32 {
Ok(OpInfo::Bank)
} else {
Err(DecodeError::InternalError(0))
match raw.Type {
ffi::_ND_OPERAND_TYPE::ND_OP_NOT_PRESENT => Ok(OpInfo::None),
ffi::_ND_OPERAND_TYPE::ND_OP_REG => {
Ok(OpInfo::Reg(OpReg::from_raw(unsafe { raw.Info.Register })?))
}
ffi::_ND_OPERAND_TYPE::ND_OP_MEM => {
Ok(OpInfo::Mem(OpMem::from_raw(unsafe { raw.Info.Memory })?))
}
ffi::_ND_OPERAND_TYPE::ND_OP_IMM => Ok(OpInfo::Imm(unsafe { raw.Info.Immediate }.Imm)),
ffi::_ND_OPERAND_TYPE::ND_OP_OFFS => {
Ok(OpInfo::Offs(unsafe { raw.Info.RelativeOffset }.Rel))
}
ffi::_ND_OPERAND_TYPE::ND_OP_ADDR => {
Ok(OpInfo::Addr(OpAddr::from_raw(unsafe { raw.Info.Address })))
}
ffi::_ND_OPERAND_TYPE::ND_OP_CONST => {
Ok(OpInfo::Const(unsafe { raw.Info.Constant }.Const))
}
ffi::_ND_OPERAND_TYPE::ND_OP_BANK => Ok(OpInfo::Bank),
}
}
}
@ -646,6 +620,7 @@ impl fmt::Display for OpSize {
impl OpSize {
pub(crate) fn from_raw(value: ffi::ND_OPERAND_SIZE) -> Result<Self, DecodeError> {
match value {
0 => Ok(OpSize::Bytes(0)),
ffi::ND_SIZE_8BIT => Ok(OpSize::Bytes(1)),
ffi::ND_SIZE_16BIT => Ok(OpSize::Bytes(2)),
ffi::ND_SIZE_32BIT => Ok(OpSize::Bytes(4)),
@ -670,7 +645,6 @@ impl OpSize {
}
/// Operand access mode.
#[allow(clippy::struct_excessive_bools)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct OpAccess {
/// The operand is read.
@ -727,6 +701,32 @@ pub struct Decorator {
pub broadcast: Option<Broadcast>,
}
#[doc(hidden)]
impl Decorator {
pub(crate) fn from_raw(raw: ffi::ND_OPERAND_DECORATOR) -> Decorator {
let mask_register = if raw.HasMask() != 0 {
Some(raw.Mask.Msk)
} else {
None
};
let broadcast = if raw.HasBroadcast() != 0 {
Some(Broadcast {
count: raw.Broadcast.Count,
size: raw.Broadcast.Size,
})
} else {
None
};
Self {
mask_register,
has_zero: raw.HasZero() != 0,
broadcast,
}
}
}
/// Describes an instruction operand.
///
/// Each operand type encodes different information. See [`OpInfo`] for details.
@ -775,11 +775,23 @@ pub struct Operand {
/// cases.
pub size: OpSize,
/// Raw size inside the instruction.
///
/// This will usually be identical to [size](Operand::size), however, some instructions force the actual size of
/// their operands to 64 bit (`PUSH`/`POP` or branches are good examples).
///
/// Although the raw size of the relative offset or the immediate will be [raw_size](Operand::raw_size), internally,
/// the CPU will use [size](Operand::size) (usually sign-extended).
pub raw_size: OpSize,
/// Access mode.
pub access: OpAccess,
/// `true` if the operand is default. This also applies to implicit operands.
pub is_default: bool,
/// Decorator information.
pub decorator: Decorator,
}
#[doc(hidden)]
@ -788,8 +800,10 @@ impl Operand {
Ok(Self {
info: OpInfo::from_raw(raw)?,
size: OpSize::from_raw(raw.Size)?,
raw_size: OpSize::from_raw(raw.RawSize)?,
access: OpAccess::from_raw(raw.Access),
is_default: unsafe { raw.Flags.__bindgen_anon_1 }.IsDefault() != 0,
decorator: Decorator::from_raw(raw.Decorator),
})
}
}
@ -918,7 +932,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn dest(&self, index: usize) -> Option<Operand> {
let op = match index {
0 => unsafe { self.op_rlut.Dst1.as_ref() },
@ -948,7 +961,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn src(&self, index: usize) -> Option<Operand> {
let op = match index {
0 => unsafe { self.op_rlut.Src1.as_ref() },
@ -979,7 +991,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn mem(&self, index: usize) -> Option<Operand> {
let op = match index {
0 => unsafe { self.op_rlut.Mem1.as_ref() },
@ -1002,7 +1013,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn stack(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Stack.as_ref() };
@ -1021,7 +1031,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn flags(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Flags.as_ref() };
@ -1040,7 +1049,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rip(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rip.as_ref() };
@ -1059,7 +1067,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn cs(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Cs.as_ref() };
@ -1078,7 +1085,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn ss(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Ss.as_ref() };
@ -1097,7 +1103,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rax(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rax.as_ref() };
@ -1116,7 +1121,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rcx(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rcx.as_ref() };
@ -1135,7 +1139,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rdx(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rdx.as_ref() };
@ -1154,7 +1157,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rbx(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rbx.as_ref() };
@ -1173,7 +1175,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rsp(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rsp.as_ref() };
@ -1192,7 +1193,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rbp(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rbp.as_ref() };
@ -1211,7 +1211,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rsi(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rsi.as_ref() };
@ -1230,7 +1229,6 @@ impl<'a> OperandsLookup<'a> {
/// This function will panic if the result of the C library is unrecognized. This can not happen under normal
/// circumstances.
#[inline]
#[must_use]
pub fn rdi(&self) -> Option<Operand> {
let op = unsafe { self.op_rlut.Rdi.as_ref() };
@ -1238,7 +1236,7 @@ impl<'a> OperandsLookup<'a> {
}
}
/// A collection of [`Operand`]s.
/// A collection of [Operand](Operand)s.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct Operands {
pub(crate) operands: [Operand; 10],
@ -1268,6 +1266,7 @@ mod tests {
let dest = operands[0];
assert_eq!(dest.size, OpSize::Bytes(1));
assert_eq!(dest.raw_size, OpSize::Bytes(1));
assert_eq!(dest.is_default, false);
assert!(dest.access.write);
@ -1282,6 +1281,7 @@ mod tests {
let src = operands[1];
assert_eq!(src.size, OpSize::Bytes(1));
assert_eq!(src.raw_size, OpSize::Bytes(1));
assert_eq!(src.is_default, false);
assert!(src.access.read);

@ -1,198 +0,0 @@
import os
import subprocess
import sys
from pathlib import Path
from git import Repo
repo = Repo(search_parent_directories=True)
root = Path(repo.working_tree_dir)
print(f"Repo root: {root}")
hdr_dirs = root / "inc"
x86_constants = hdr_dirs / "bdx86_constants.h"
print(f"Looking for enums in {x86_constants}")
with open(x86_constants, "r") as data:
nd_ins = []
nd_ins_set = []
nd_ins_type = []
for line in data:
if "INVALID" in line:
continue
if line.startswith(" ND_CAT_"):
token = line.replace(',', '').strip()
nd_ins_type.append(token)
continue
if line.startswith(" ND_SET_"):
token = line.replace(',', '').strip()
nd_ins_set.append(token)
continue
if line.startswith(" ND_INS_"):
token = line.replace(',', '').strip()
nd_ins.append(token)
continue
print(f"ND_INS_: {len(nd_ins)} ND_SET_: {len(nd_ins_set)} ND_CAT_: {len(nd_ins_type)}")
bindings = root / "bindings/rsbddisasm/bddisasm/src"
mnemonic = bindings / "mnemonic.rs"
ins_cat = bindings / "instruction_category.rs"
isa_set = bindings / "isa_set.rs"
license_header = """
/*
* Copyright (c) 2021 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
"""
print(f"Generating {mnemonic}")
with open(mnemonic, "w") as fmnemonic:
fmnemonic.write(license_header)
fmnemonic.write("//! Mnemonics.\n")
fmnemonic.write("\n")
fmnemonic.write("use super::decode_error::DecodeError;\n")
fmnemonic.write("use core::convert::TryFrom;\n")
mnemonic_enum_def = """
/// Uniquely identifies an instruction.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[allow(non_camel_case_types)]
pub enum Mnemonic {
"""
fmnemonic.write(mnemonic_enum_def)
for ins in nd_ins:
line = ins.replace("ND_INS_", "")
fmnemonic.write(f"{line},\n")
fmnemonic.write("}\n")
try_from = """
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_CLASS) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_CLASS::ND_INS_INVALID => Err(DecodeError::InternalError(value as u64)),
"""
fmnemonic.write(try_from)
for ins in nd_ins:
line = f"ffi::_ND_INS_CLASS::{ins} => Ok(Mnemonic::{ins.replace('ND_INS_', '')}),\n"
fmnemonic.write(line)
end = """
}
}
}
"""
fmnemonic.write(end)
print(f"Generating {ins_cat}")
with open(ins_cat, "w") as finscat:
finscat.write(license_header)
finscat.write("//! Instruction categories.\n")
finscat.write("\n")
finscat.write("use super::decode_error::DecodeError;\n")
finscat.write("use core::convert::TryFrom;\n")
ins_cat_enum_def = """
/// Instruction category.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[allow(non_camel_case_types)]
pub enum Category {
"""
finscat.write(ins_cat_enum_def)
for ins in nd_ins_type:
line = ins.replace("ND_CAT_", "")
if line[0].isdigit():
line = f"I{line}"
finscat.write(f"{line},\n")
finscat.write("}\n")
try_from = """
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_CATEGORY) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_TYPE::ND_CAT_INVALID => Err(DecodeError::InternalError(value as u64)),
"""
finscat.write(try_from)
for ins in nd_ins_type:
ok = ins.replace('ND_CAT_', '')
if ok[0].isdigit():
ok = f"I{ok}"
line = f"ffi::_ND_INS_TYPE::{ins} => Ok(Category::{ok}),\n"
finscat.write(line)
end = """
}
}
}
"""
finscat.write(end)
print(f"Generating {isa_set}")
with open(isa_set, "w") as fset:
fset.write(license_header)
fset.write("//! Instruction sets.\n")
fset.write("\n")
fset.write("use super::decode_error::DecodeError;\n")
fset.write("use core::convert::TryFrom;\n")
ins_set_enum_def = """
/// ISA set.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[allow(non_camel_case_types)]
pub enum IsaSet {
"""
fset.write(ins_set_enum_def)
for ins in nd_ins_set:
line = ins.replace("ND_SET_", "")
if line[0].isdigit():
line = f"I{line}"
fset.write(f"{line},\n")
fset.write("}\n")
try_from = """
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_SET> for IsaSet {
type Error = DecodeError;
#[allow(clippy::too_many_lines)]
fn try_from(value: ffi::ND_INS_SET) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_SET::ND_SET_INVALID => Err(DecodeError::InternalError(value as u64)),
"""
fset.write(try_from)
for ins in nd_ins_set:
ok = ins.replace('ND_SET_', '')
if ok[0].isdigit():
ok = f"I{ok}"
line = f"ffi::_ND_INS_SET::{ins} => Ok(IsaSet::{ok}),\n"
fset.write(line)
end = """
}
}
}
"""
fset.write(end)
subprocess.check_output(["cargo", "fmt"])

@ -50,7 +50,9 @@ else ()
-Wno-unused-function
-Wno-multichar
-Wno-incompatible-pointer-types
-Wno-discarded-qualifiers
-Wnull-dereference
-Wduplicated-cond
-Werror=implicit-function-declaration
-pipe
-fwrapv
@ -63,10 +65,4 @@ else ()
-gdwarf-4
-grecord-gcc-switches
-march=westmere)
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_compile_options(
disasmtool
PRIVATE -Wno-discarded-qualifiers
-Wduplicated-cond)
endif ()
endif ()

File diff suppressed because it is too large Load Diff

@ -5,24 +5,6 @@
#ifndef DISASMTOOL_H
#define DISASMTOOL_H
#include <stdbool.h>
#include <stdint.h>
#ifndef WIN32
#define _In_
#define _Inout_
#define _Out_
#define _Success_(x)
typedef char CHAR, *PCHAR;
typedef unsigned char BYTE, *PBYTE;
typedef int32_t INT32;
typedef uint32_t DWORD;
#define UNREFERENCED_PARAMETER(P) (void)(P)
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif // !WIN32
typedef enum _DISASM_COMMAND
{
@ -47,24 +29,26 @@ typedef struct _DISASM_OPTIONS
size_t Size; // Buffer size.
size_t Offset; // Offset inside the buffer.
size_t Rip; // Virtual RIP.
bool Highlight; // Highlight instruction components, if true.
bool ExtendedInfo; // Display extended instruction info, if true.
bool BitFields; // Display the various bitfields inside the instruction, if true.
bool Skip16; // Automatically jump over 16 bytes after each instruction.
bool Skip1; // Automatically jump over one single byte after each instruction.
bool Stats; // Display disassembly stats (clocks / instruction, instructions / second), if true.
bool Print; // Print instruction disassembly, if true.
BOOLEAN Highlight; // Highlight instruction components, if true.
BOOLEAN ExtendedInfo; // Display extended instruction info, if true.
BOOLEAN BitFields; // Display the various bitfields inside the instruction, if true.
BOOLEAN Skip16; // Automatically jump over 16 bytes after each instruction.
BOOLEAN Stats; // Display disassembly stats (clocks / instruction, instructions / second), if true.
BOOLEAN Print; // Print instruction disassembly, if true.
uint8_t Mode; // Mode - 16, 32 or 64-bit mode.
uint8_t Ring; // Ring - 0, 1, 2 or 3.
uint8_t Vendor; // Preffered vendor.
uint8_t Feature; // Used features.
char *FileName; // Input file, if any.
size_t ShemuRegs[ND_MAX_GPR_REGS];
bool UseShemuRegs; // If truue, the registers in ShemuRegs will be used for shemu input.
bool BypassSelfWrites; // If true, shemu emulation will ignore self-modifications made by the shellcode.
BOOLEAN UseShemuRegs; // If truue, the registers in ShemuRegs will be used for shemu input.
BOOLEAN BypassSelfWrites; // If true, shemu emulation will ignore self-modifications made by the shellcode.
// Internal.
INPUT_MODE InputMode;
HANDLE HandleFile;
HANDLE HandleMapping;
} DISASM_OPTIONS, *PDISASM_OPTIONS;

@ -0,0 +1,65 @@
cmake_minimum_required(VERSION 3.16)
project(disasmtool LANGUAGES CXX)
# Use Release as the build type if no build type was specified and we're not using a multi-config generator .
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "No build type given. Will use 'Release'")
set(CMAKE_BUILD_TYPE
"Release"
CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui.
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif ()
add_executable(disasmtool disasmtool.cpp dumpers.cpp rapidjson.cpp)
target_compile_options(
disasmtool
PRIVATE "$<$<CONFIG:Release>:-U_FORTIFY_SOURCE>"
"$<$<CONFIG:Release>:-D_FORTIFY_SOURCE=2>"
-Wall
-Wextra
-Wshadow
-Wformat-security
-Wstrict-overflow=2
-Wno-unused-function
-Wno-multichar
-Werror=format-security
-pipe
-fpie
-fwrapv
-fno-strict-aliasing
-fstack-protector-strong
-ffunction-sections
-fdata-sections
-g3
-gdwarf-4
-grecord-gcc-switches
-march=nehalem
-fno-omit-frame-pointer)
if (NOT TARGET bddisasm)
find_package(bddisasm REQUIRED)
endif ()
find_package(RapidJSON QUIET REQUIRED)
target_link_libraries(disasmtool PRIVATE bddisasm::bddisasm bddisasm::bdshemu)
# :( https://github.com/satishbabariya/modern-cmake#good-boys-export-their-targets
target_include_directories(disasmtool PRIVATE ${RapidJSON_INCLUDE_DIRS})
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
include(CheckIPOSupported)
check_ipo_supported(RESULT USE_IPO)
if (USE_IPO)
set_target_properties(disasmtool PROPERTIES INTERPROCEDURAL_OPTIMIZATION True)
endif ()
endif ()
set_target_properties(
disasmtool
PROPERTIES POSITION_INDEPENDENT_CODE ON
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS ON)

@ -0,0 +1,39 @@
.PHONY: all last_build debug release
CMAKE_BUILD_DIR = build
CPUCOUNT := $(shell grep -c "^processor" /proc/cpuinfo)
ifneq (,$(CPUCOUNT))
EXTRA_MAKE_ARGS := -j$(CPUCOUNT)
endif
# NINJA := $(shell which ninja 2>/dev/null)
ifneq (,$(NINJA))
GENERATOR := "Ninja"
else
GENERATOR := "Unix Makefiles"
endif
$(shell if [ ! -d $(CMAKE_BUILD_DIR) ]; then mkdir $(CMAKE_BUILD_DIR); fi)
all: last_build
last_build:
@cmake -H. -G$(GENERATOR) -B$(CMAKE_BUILD_DIR) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
@cmake --build $(CMAKE_BUILD_DIR) -- $(EXTRA_MAKE_ARGS)
debug: CMAKE_BUILD_TYPE := Debug
debug: build
release: CMAKE_BUILD_TYPE := Release
release: build
clean:
@if [ -d $(CMAKE_BUILD_DIR) ]; then cmake --build $(CMAKE_BUILD_DIR) --target clean; fi
reset:
@if [ -d $(CMAKE_BUILD_DIR) ]; then rm -r $(CMAKE_BUILD_DIR); fi

@ -0,0 +1,66 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <ctime>
#include <cstdint>
#include <rapidjson/stringbuffer.h>
using StringBuffer = rapidjson::StringBuffer;
extern "C"
{
// On windows, simply include Windows.h
#ifndef _WIN32
typedef void VOID, *PVOID;
typedef unsigned char BOOLEAN, *PBOOLEAN;
typedef char CHAR, *PCHAR;
typedef unsigned char BYTE, *PBYTE;
typedef unsigned short WORD, *PWORD;
typedef unsigned int DWORD, *PDWORD;
typedef unsigned long long QWORD, *PQWORD;
typedef size_t SIZE_T;
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef MAX_PATH
#define MAX_PATH 255
#endif
// Main disasm header file.
#include "bdshemu.h"
#include "bddisasm.h"
#include <unistd.h>
#include <time.h>
}
#include <string>
std::string enc_mode_to_str(const uint8_t enc_mode);
std::string op_type_to_str(const ND_OPERAND_TYPE type);
std::string op_enc_to_str(const ND_OPERAND_ENCODING Encoding);
std::string ins_class_to_str(const ND_INS_CLASS cls);
std::string ins_cat_to_str(ND_INS_CATEGORY category);
std::string ins_set_to_str(ND_INS_SET ins_set);
std::string reg_to_str(const int reg, const ND_REG_TYPE type);
std::string reg_type_to_str(const ND_REG_TYPE type);
StringBuffer instrux_to_json(INSTRUX *instrux, size_t rip, bool text_only = false);
StringBuffer byte_to_json(uint8_t byte, size_t rip);
StringBuffer disassemble_one(uint8_t *bytes, size_t size, size_t rip, uint8_t bits, uint8_t vendor = ND_VEND_INTEL);
bool regs_from_json(const std::string &str, SHEMU_GPR_REGS &regs, bool &update_rsp);

@ -0,0 +1,927 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include <iostream>
#include <fstream>
#include <memory>
#include <limits>
#include <cmath>
#include <cpuid.h>
#include "external/argparse.h"
#include "disasm.hpp"
#define STACK_SIZE 0x2000
#define PAGE_MASK 0xFFFFFFFFFFFFF000
static const long NSEC_PER_SEC = (1000ULL * 1000ULL * 1000ULL);
static const char *gSpaces[16] =
{
"",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
};
struct options {
size_t rip;
size_t offset;
size_t size;
size_t count;
uint8_t bits;
uint8_t vendor;
bool no_color;
bool verbose;
bool dump_stats;
bool interactive;
bool comm;
bool json_output;
bool extended;
bool shemu;
std::string shctx;
bool kernel;
std::string in_file;
std::string hex_string;
std::string hex_file;
std::string shctx_file;
std::string shdec_file;
// From here on, these are set internally
std::unique_ptr<uint8_t[]> bytes;
size_t actual_size;
int address_size;
bool output_redirected;
};
extern "C"
{
#if !defined(BDDISASM_HAS_VSNPRINTF)
int nd_vsnprintf_s(char *buffer, size_t sizeOfBuffer, [[maybe_unused]] size_t count, const char *format, va_list argptr)
{
return vsnprintf(buffer, sizeOfBuffer, format, argptr);
}
#endif // !defined(BDDISASM_HAS_VSNPRINTF)
#if !defined(BDDISASM_HAS_MEMSET)
void *
nd_memset(void *s, int c, size_t n)
{
return memset(s, c, n);
}
#endif // !defined(BDDISASM_HAS_MEMSET)
}
static bool _hexstring_to_bytes(options &opts)
{
if (!opts.hex_file.empty()) {
auto f = std::ifstream(opts.hex_file, std::ios::in);
if (!f.is_open()) {
std::cerr << "Failed to open file " << opts.hex_file << std::endl;
return false;
}
f.seekg(0, std::ios::end);
opts.hex_string.reserve(f.tellg());
f.seekg(0, std::ios::beg);
opts.hex_string.assign((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
}
if (opts.hex_string.empty())
return false;
opts.actual_size = 0;
opts.hex_string.erase(std::remove_if(opts.hex_string.begin(), opts.hex_string.end(), isspace), opts.hex_string.end());
// This is the maximum size, not the actual size
auto initial_size = opts.hex_string.length() / 2 + 1;
opts.bytes = std::make_unique<uint8_t[]>(initial_size);
auto bytes = opts.bytes.get();
for (size_t i = 0; i < opts.hex_string.length(); i += 2) {
auto pair = opts.hex_string.substr(i, 2);
char *end_ptr;
if (pair == "0x" || pair == "0X" || pair == "\\x")
continue;
auto b = static_cast<uint8_t>(std::strtoul(pair.c_str(), &end_ptr, 16));
size_t conv_size = static_cast<size_t>(end_ptr - pair.c_str());
if (conv_size != pair.length()) {
std::cerr << "Trying to convert invalid hex number: " << pair << std::endl;
return false;
}
bytes[opts.actual_size++] = b;
}
return true;
}
static bool _load_shctx(options &opts)
{
if (opts.shctx_file.empty())
return false;
auto f = std::ifstream(opts.shctx_file, std::ios::in);
if (!f.is_open()) {
std::cout << "Failed to open file " << opts.shctx_file << std::endl;
return false;
}
f.seekg(0, std::ios::end);
opts.shctx.reserve(f.tellg());
f.seekg(0, std::ios::beg);
opts.shctx.assign((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
return true;
}
static bool _file_to_bytes(options &opts)
{
auto f = std::ifstream(opts.in_file, std::ios::in | std::ios::binary);
if (!f.is_open()) {
std::cerr << "Failed to open file " << opts.in_file << std::endl;
return false;
}
f.seekg(0, std::ios::end);
opts.actual_size = f.tellg();
if (opts.offset >= opts.actual_size) {
std::cerr << "Offset bigger than file size" << std::endl;
return false;
}
f.seekg(0, std::ios::beg);
opts.bytes = std::make_unique<uint8_t[]>(opts.actual_size);
f.read(reinterpret_cast<char*>(opts.bytes.get()), opts.actual_size);
return true;
}
// Don't change the order (on linux these values are color codes)
enum Colors {
Reset = 0,
#if defined(_WIN32)
Red = FOREGROUND_INTENSITY | FOREGROUND_RED,
Green = FOREGROUND_INTENSITY | FOREGROUND_GREEN,
Yellow = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
Blue = FOREGROUND_INTENSITY | FOREGROUND_BLUE,
Magenta = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_RED,
Cyan = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN,
White = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED,
#elif defined(__unix__)
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
#endif
};
static void _set_text_color(Colors color)
{
#if defined(_WIN32)
static WORD old_attrs = -1;
if (old_attrs == -1) {
CONSOLE_SCREEN_BUFFER_INFO buffer_info;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &buffer_info);
old_attrs = buffer_info.wAttributes;
}
if (color == Reset)
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), old_attrs);
else
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
#elif defined(__unix__)
if (color == Reset)
std::cout << "\033[m";
else
std::cout << "\033[0;3" << color << "m";
#endif
}
static struct timespec diff_time(struct timespec const &end, struct timespec const &start)
{
struct timespec result;
if (end.tv_nsec > start.tv_nsec) {
result.tv_sec = end.tv_sec - start.tv_sec;
result.tv_nsec = end.tv_nsec - start.tv_nsec;
} else {
result.tv_sec = end.tv_sec - start.tv_sec - 1;
result.tv_nsec = NSEC_PER_SEC + end.tv_nsec - start.tv_nsec;
}
return result;
}
void print_instruction(const size_t rip, INSTRUX *instrux, const options &opts)
{
char instruxText[ND_MIN_BUF_SIZE];
uint32_t k = 0;
printf("%*zx ", opts.address_size, rip);
if (!opts.no_color)
{
_set_text_color(Magenta);
for (uint32_t idx = 0; idx < instrux->PrefLength; idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
_set_text_color(Green);
for (uint32_t idx = 0; idx < (DWORD)(ND_IS_3DNOW(instrux) ? instrux->OpLength - 1 : instrux->OpLength); idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
_set_text_color(Yellow);
for (uint32_t idx = 0; idx < (DWORD)(instrux->HasModRm + instrux->HasSib); idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
_set_text_color(Blue);
for (uint32_t idx = 0; idx < (DWORD)(instrux->DispLength); idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
_set_text_color(Red);
for (uint32_t idx = 0; idx < (DWORD)(instrux->Imm1Length + instrux->Imm2Length +
instrux->RelOffsLength + instrux->MoffsetLength +
instrux->HasSseImm + instrux->AddrLength); idx++, k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
if (ND_IS_3DNOW(instrux))
{
_set_text_color(Green);
for (; k < instrux->Length; k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
}
_set_text_color(Reset);
}
for (; k < instrux->Length; k++)
{
printf("%02x", instrux->InstructionBytes[k]);
}
std::cout << gSpaces[16 - instrux->Length];
NdToText(instrux, rip, sizeof(instruxText), instruxText);
std::cout << instruxText << std::endl;
if (opts.extended) {
const uint8_t opsize[3] = { 2, 4, 8 };
const uint8_t adsize[3] = { 2, 4, 8 };
const uint8_t veclen[3] = { 16, 32, 64 };
printf(" DSIZE: %2d, ASIZE: %2d, VLEN: ",
opsize[instrux->EfOpMode] * 8, adsize[instrux->AddrMode] * 8);
if (ND_HAS_VECTOR(instrux)) {
printf("%2d\n", veclen[instrux->VecMode] * 8);
} else {
printf("-\n");
}
printf(" ISA Set: %s, Ins cat: %s, Ins class: %d, CET tracked: %s\n",
ins_set_to_str(instrux->IsaSet).c_str(), ins_cat_to_str(instrux->Category).c_str(), instrux->Instruction,
instrux->IsCetTracked ? "yes" : "no");
if (0 != instrux->CpuidFlag.Flag) {
const char *regs[4] = { "eax", "ecx", "edx", "ebx" };
printf(" CPUID leaf: 0x%08x", instrux->CpuidFlag.Leaf);
if (instrux->CpuidFlag.SubLeaf != ND_CFF_NO_SUBLEAF)
{
printf(", sub-leaf: 0x%08x", instrux->CpuidFlag.SubLeaf);
}
printf(", reg: %s, bit %u\n", regs[instrux->CpuidFlag.Reg], instrux->CpuidFlag.Bit);
}
printf(" FLAGS access: ");
uint32_t all = instrux->FlagsAccess.Tested.Raw | instrux->FlagsAccess.Modified.Raw | instrux->FlagsAccess.Set.Raw
| instrux->FlagsAccess.Cleared.Raw | instrux->FlagsAccess.Undefined.Raw;
const char *flags[22] = { "CF", nullptr, "PF", nullptr, "AF", nullptr, "ZF", "SF", "TF", "IF", "DF", "OF", "IOPL", nullptr, "NT", nullptr, "RF", "VM", "AC", "VIF", "VIP", "ID" };
for (uint32_t fidx = 0; fidx < 21; fidx++) {
if (flags[fidx] != nullptr) {
if (0 == (all & (1ULL << fidx))) {
continue;
}
printf("%s: ", flags[fidx]);
if (instrux->FlagsAccess.Tested.Raw & (1ULL << fidx)) {
printf("t");
}
if (instrux->FlagsAccess.Modified.Raw & (1ULL << fidx)) {
printf("m");
}
if (instrux->FlagsAccess.Set.Raw & (1ULL << fidx)) {
printf("1");
}
if (instrux->FlagsAccess.Cleared.Raw & (1ULL << fidx)) {
printf("0");
}
if (instrux->FlagsAccess.Undefined.Raw & (1ULL << fidx)) {
printf("u");
}
printf("; ");
}
}
printf("\n");
printf(" Valid modes: R0: %s, R1: %s, R2: %s, R3: %s, Real: %s, V8086: %s, Prot: %s, Compat: %s, Long: %s, SMM: %s, SGX: %s, TSX: %s, VMXRoot: %s, VMXNonRoot: %s\n",
instrux->ValidModes.Ring0 ? "yes" : "no",
instrux->ValidModes.Ring1 ? "yes" : "no",
instrux->ValidModes.Ring2 ? "yes" : "no",
instrux->ValidModes.Ring3 ? "yes" : "no",
instrux->ValidModes.Real ? "yes" : "no",
instrux->ValidModes.V8086 ? "yes" : "no",
instrux->ValidModes.Protected ? "yes" : "no",
instrux->ValidModes.Compat ? "yes" : "no",
instrux->ValidModes.Long ? "yes" : "no",
instrux->ValidModes.Smm ? "yes" : "no",
instrux->ValidModes.Sgx ? "yes" : "no",
instrux->ValidModes.Tsx ? "yes" : "no",
instrux->ValidModes.VmxRoot ? "yes" : "no",
instrux->ValidModes.VmxNonRoot ? "yes" : "no");
for (uint8_t i = 0; i < instrux->OperandsCount; i++) {
printf(" Operand %d %s Type: %10s, Size: %2d, RawSize: %2d, Encoding: %s", i,
instrux->Operands[i].Access.Read && instrux->Operands[i].Access.Write ? "RW" :
instrux->Operands[i].Access.Write ? "-W" : instrux->Operands[i].Access.Read ? "R-" : "--",
op_type_to_str(instrux->Operands[i].Type).c_str(), (int)instrux->Operands[i].Size,
(int)instrux->Operands[i].RawSize, op_enc_to_str(instrux->Operands[i].Encoding).c_str());
if (ND_OP_MEM == instrux->Operands[i].Type) {
printf(", ");
if (instrux->Operands[i].Info.Memory.IsAG) {
printf("Address Generator, ");
}
if (instrux->Operands[i].Info.Memory.IsBitbase) {
printf("Bitbase Addressing, ");
}
if (instrux->Operands[i].Info.Memory.IsMib) {
printf("MIB Addressing, ");
}
if (instrux->Operands[i].Info.Memory.IsVsib) {
printf("VSIB Addressing, ");
}
if (instrux->Operands[i].Info.Memory.IsStack) {
printf("Stack, ");
}
if (instrux->Operands[i].Info.Memory.IsShadowStack) {
printf("Shadow Stack, ");
}
}
if (ND_OP_REG == instrux->Operands[i].Type) {
printf(", RegType: %16s, RegSize: %2u, ",
reg_type_to_str(instrux->Operands[i].Info.Register.Type).c_str(),
instrux->Operands[i].Info.Register.Size);
if (instrux->Operands[i].Info.Register.Type == ND_REG_MSR)
{
printf("RegId: 0x%08x, RegCount: %u\n",
instrux->Operands[i].Info.Register.Reg,
instrux->Operands[i].Info.Register.Count);
}
else
{
printf("RegId: %u, RegCount: %u\n",
instrux->Operands[i].Info.Register.Reg,
instrux->Operands[i].Info.Register.Count);
}
}
printf("\n");
if (instrux->Operands[i].Decorator.HasBroadcast) {
printf(" Decorator: Broadcast %d bytes element %d times\n",
instrux->Operands[i].Decorator.Broadcast.Size,
instrux->Operands[i].Decorator.Broadcast.Count);
}
if (instrux->Operands[i].Decorator.HasMask) {
printf(" Decorator: Mask k%d\n", instrux->Operands[i].Decorator.Mask.Msk);
}
if (instrux->Operands[i].Decorator.HasZero) {
printf(" Decorator: Zero (no merging)\n");
}
}
printf("\n");
}
}
StringBuffer disassemble_one(uint8_t *bytes, size_t size, size_t rip, uint8_t bits, uint8_t vendor /* = ND_VEND_INTEL */)
{
INSTRUX instrux;
auto status = NdDecodeEx2(&instrux, bytes, size, bits, bits, bits, vendor);
if (!ND_SUCCESS(status))
return byte_to_json(bytes[0], rip);
else
return instrux_to_json(&instrux, rip);
}
void shemu_log(PCHAR msg)
{
printf("%s", msg);
}
ND_BOOL shemu_access_mem(void * /* Ctx */, uint64_t /* Gla */, size_t Size, uint8_t *Buffer, ND_BOOL Store)
{
if (!Store)
{
memset(Buffer, 0, Size);
}
return ND_TRUE;
}
void shemu(options &opts)
{
SHEMU_CONTEXT ctx = { };
SHEMU_STATUS shstatus;
auto stack = std::make_unique<uint8_t[]>(STACK_SIZE);
auto intbuf = std::make_unique<uint8_t[]>(opts.actual_size + STACK_SIZE);
auto shellcode = std::make_unique<uint8_t[]>(opts.actual_size);
ctx.Stack = stack.get();
memset(ctx.Stack, 0, STACK_SIZE);
ctx.Intbuf = intbuf.get();
memset(ctx.Intbuf, 0, opts.actual_size + STACK_SIZE);
ctx.Shellcode = shellcode.get();
memcpy(ctx.Shellcode, opts.bytes.get(), opts.actual_size);
ctx.ShellcodeSize = opts.actual_size;
ctx.StackSize = STACK_SIZE;
ctx.Registers.RegRsp = 0x101000;
ctx.IntbufSize = opts.actual_size + STACK_SIZE;
ctx.Registers.RegFlags = NDR_RFLAG_IF | 2;
ctx.Registers.RegRip = opts.rip ? opts.rip : 0x200000;
ctx.Segments.Cs.Selector = 0x10;
ctx.Segments.Ds.Selector = 0x28;
ctx.Segments.Es.Selector = 0x28;
ctx.Segments.Ss.Selector = 0x28;
ctx.Segments.Fs.Selector = 0x30;
ctx.Segments.Fs.Base = 0x7FFF0000;
ctx.Segments.Gs.Selector = 0x30;
ctx.Segments.Gs.Base = 0x7FFF0000;
// Dummy values, to resemble regular CR0/CR4 values.
ctx.Registers.RegCr0 = 0x0000000080050031;
ctx.Registers.RegCr4 = 0x0000000000170678;
ctx.Mode = opts.bits;
ctx.Ring = opts.kernel ? 0 : 3;
ctx.TibBase = (opts.bits == ND_DATA_32 ? ctx.Segments.Fs.Base : ctx.Segments.Gs.Base);
ctx.MaxInstructionsCount = 4096;
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;
ctx.StrThreshold = SHEMU_DEFAULT_STR_THRESHOLD;
ctx.MemThreshold = SHEMU_DEFAULT_MEM_THRESHOLD;
bool update_rsp = false;
if (!opts.shctx.empty() && !regs_from_json(opts.shctx, ctx.Registers, update_rsp)) {
std::cerr << "Failed to parse context file." << std::endl;
return;
}
// Consider the stack base at least with a page before the current RSP. In case of pushes or operations
// which decrease the RSP, we will always give SHEMU_ABORT_BRANCH_OUTSIDE otherwise.
ctx.StackBase = ctx.Registers.RegRsp - 0x1000;
ctx.ShellcodeBase = (ctx.Registers.RegRip ? ctx.Registers.RegRip & PAGE_MASK : 0x200000);
shstatus = ShemuEmulate(&ctx);
printf("Emulation terminated with status 0x%08x, flags: 0x%llx, %u NOPs\n",
shstatus, (unsigned long long)ctx.Flags, ctx.NopCount);
if (ctx.Flags & SHEMU_FLAG_NOP_SLED)
{
printf(" SHEMU_FLAG_NOP_SLED\n");
}
if (ctx.Flags & SHEMU_FLAG_LOAD_RIP)
{
printf(" SHEMU_FLAG_LOAD_RIP\n");
}
if (ctx.Flags & SHEMU_FLAG_WRITE_SELF)
{
printf(" SHEMU_FLAG_WRITE_SELF\n");
}
if (ctx.Flags & SHEMU_FLAG_TIB_ACCESS)
{
printf(" SHEMU_FLAG_TIB_ACCESS\n");
}
if (ctx.Flags & SHEMU_FLAG_SYSCALL)
{
printf(" SHEMU_FLAG_SYSCALL\n");
}
if (ctx.Flags & SHEMU_FLAG_STACK_STR)
{
printf(" SHEMU_FLAG_STACK_STR\n");
}
if (ctx.Flags & SHEMU_FLAG_KPCR_ACCESS)
{
printf(" SHEMU_FLAG_KPCR_ACCESS\n");
}
if (ctx.Flags & SHEMU_FLAG_SWAPGS)
{
printf(" SHEMU_FLAG_SWAPGS\n");
}
if (ctx.Flags & SHEMU_FLAG_SYSCALL_MSR_READ)
{
printf(" SHEMU_FLAG_SYSCALL_MSR_READ\n");
}
if (ctx.Flags & SHEMU_FLAG_SYSCALL_MSR_WRITE)
{
printf(" SHEMU_FLAG_SYSCALL_MSR_WRITE\n");
}
if (!opts.shdec_file.empty()) {
auto f = std::ofstream(opts.shdec_file, std::ios::out | std::ios::binary);
if (!f.is_open())
std::cerr << "Failed to open file " << opts.shdec_file<< std::endl;
else
f.write(reinterpret_cast<char*>(ctx.Shellcode), ctx.ShellcodeSize);
}
}
size_t disassemble(options &opts)
{
struct timespec start;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
size_t icount = 0, miss_count = 0, ibytes = 0;
size_t rel_rip = opts.offset;
size_t total_disasm = 0;
auto bytes = opts.bytes.get();
auto disasm_size = std::min(opts.actual_size - opts.offset, opts.size);
opts.address_size = int(std::ceil(((8 * sizeof(opts.actual_size)) - __builtin_clzll(opts.actual_size)) / 4.0));
while ((total_disasm < disasm_size) && (icount < opts.count)) {
INSTRUX instrux;
auto status = NdDecodeEx2(&instrux,
&bytes[rel_rip],
opts.actual_size - rel_rip,
opts.bits,
opts.bits,
opts.bits,
opts.vendor);
if (!ND_SUCCESS(status)) {
if (!opts.dump_stats) {
if (opts.json_output) {
auto j = byte_to_json(bytes[rel_rip], rel_rip + opts.rip);
std::cout << j.GetString() << std::endl;
} else {
printf("%*zx ", opts.address_size, rel_rip + opts.rip);
printf("%02x", bytes[rel_rip]);
printf("%s", gSpaces[16 - opts.address_size]);
printf("db 0x%02x\n", bytes[rel_rip]);
}
}
rel_rip++;
total_disasm++;
miss_count++;
} else {
icount++;
ibytes += instrux.Length;
if (!opts.dump_stats) {
if (opts.json_output) {
auto j = instrux_to_json(&instrux, rel_rip + opts.rip);
std::cout << j.GetString() << std::endl;
} else
print_instruction(rel_rip + opts.rip, &instrux, opts);
} else if (opts.json_output)
instrux_to_json(&instrux, rel_rip + opts.rip);
rel_rip += instrux.Length;
total_disasm += instrux.Length;
}
}
struct timespec end;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
if (opts.dump_stats)
{
auto result = diff_time(end, start);
long total_ns = result.tv_sec * NSEC_PER_SEC + result.tv_nsec;
printf("Disassembled %zu instructions took %ld.%09ld seconds, %lu ns / instr.\n",
icount, result.tv_sec, result.tv_nsec, total_ns / icount);
printf("Invalid: %zu/%zu (%.2f) bytes\n", miss_count, ibytes,
(static_cast<double>(miss_count) / static_cast<double>(disasm_size)) * 100.0);
}
opts.rip += rel_rip;
return icount;
}
static bool _validate_and_fix_args(options& opts)
{
if (!opts.interactive && !opts.comm) {
int total = 0;
if (!opts.hex_string.empty())
total++;
if (!opts.hex_file.empty())
total++;
if (!opts.in_file.empty())
total++;
if (total == 0) {
std::cerr << "Give hex, file or hex-file..." << std::endl;
return false;
} else if (total > 1) {
std::cerr << "Only one of hex, file or hex-file can be present..." << std::endl;
return false;
}
}
if (opts.interactive || opts.comm) {
if (!opts.in_file.empty() || !opts.hex_string.empty() || !opts.hex_file.empty()) {
std::cerr << "Interactive mode doesn't work with file, hex-string or hex-file" << std::endl;
return false;
}
if (opts.size || opts.count || opts.offset) {
std::cerr << "Interactive mode doesn't work with size, count or offset" << std::endl;
return false;
}
}
switch (opts.bits) {
case 64:
opts.bits = ND_DATA_64;
break;
case 32:
opts.bits = ND_DATA_32;
break;
case 16:
opts.bits = ND_DATA_16;
break;
default:
std::cerr << "Please give --bits [64,32,16]" << std::endl;
return false;
}
if (0 == opts.size)
opts.size = std::numeric_limits<std::size_t>::max();
if (0 == opts.count)
opts.count = std::numeric_limits<std::size_t>::max();
if (!isatty(fileno(stdout)))
opts.output_redirected = true;
if (!opts.hex_file.empty())
opts.shdec_file = opts.hex_file + "_decoded.bin";
else if (!opts.in_file.empty())
opts.shdec_file = opts.in_file + "_decoded.bin";
else
opts.shdec_file = "hex_string_decoded.bin";
return true;
}
static size_t _get_hex_opt(argparse::ArgumentParser &parser, const std::string &field)
{
return std::strtoul(parser.get<std::string>(field).c_str(), nullptr, 0);
}
int main(int argc, const char **argv)
{
auto opts = options{};
auto parser = argparse::ArgumentParser(argv[0], "Disassembler tool for Linux");
parser.add_argument("-i", "--interactive", "Interactive mode", false);
parser.add_argument("-c", "--comm", "Comm mode", false);
parser.add_argument("-r", "--rip", "Use this rip to disassemble", false);
parser.add_argument("-f", "--file", "Use this input file", false);
parser.add_argument("-x", "--hex", "Use this hex-string", false);
parser.add_argument("--hexfile", "Use this input file as a hex-string", false);
parser.add_argument("--no-color", "Don't use colors", false);
parser.add_argument("--offset", "Use this offset in file/hex-string", false);
parser.add_argument("--size", "Only disasemble this size from file/hex-string", false);
parser.add_argument("--count", "Only disasemble this many instructions", false);
parser.add_argument("--stats", "Dump statistics (time, count, etc.)", false);
parser.add_argument("-b", "--bits", "Use the arch [16, 32, 64]", false);
parser.add_argument("--verbose", "Verbose mode", false);
parser.add_argument("--json", "Output to json", false);
parser.add_argument("--extended", "Extended instruction info", false);
parser.add_argument("--shemu", "Emulate the input hexfile", false);
parser.add_argument("--kernel", "Kernel mode for shemu context", false);
parser.add_argument("--shctx", "Shemu context file. Must be a JSON file.", false);
parser.enable_help();
auto err = parser.parse(argc, argv);
if (err) {
std::cout << err << std::endl;
return -1;
}
if (parser.exists("help")) {
parser.print_help();
return 0;
}
opts.bits = parser.get<uint64_t>("bits");
opts.interactive = parser.exists("interactive");
opts.comm = parser.exists("comm");
opts.offset = _get_hex_opt(parser, "offset");
opts.size = _get_hex_opt(parser, "size");
opts.count = _get_hex_opt(parser, "count");
opts.rip = _get_hex_opt(parser, "rip");
opts.in_file = parser.get<std::string>("file");
opts.hex_string = parser.get<std::string>("hex");
opts.hex_file = parser.get<std::string>("hexfile");
opts.no_color = parser.exists("no-color");
opts.dump_stats = parser.exists("stats");
opts.verbose = parser.exists("verbose");
opts.json_output = parser.exists("json");
opts.extended = parser.exists("extended");
opts.shemu = parser.exists("shemu");
opts.kernel = parser.exists("kernel");
opts.shctx_file = parser.get<std::string>("shctx");
if (opts.verbose) {
std::cout << "interactive: " << opts.interactive << std::endl;
std::cout << "comm: " << opts.comm << std::endl;
std::cout << "rip: " << opts.rip << std::endl;
std::cout << "bits: " << static_cast<uint16_t>(opts.bits) << std::endl;
std::cout << "offset: " << opts.offset << std::endl;
std::cout << "size: " << opts.offset << std::endl;
std::cout << "count: " << opts.count << std::endl;
std::cout << "in_file: " << opts.in_file << std::endl;
std::cout << "no-color: " << opts.no_color << std::endl;
std::cout << "stats: " << opts.dump_stats << std::endl;
std::cout << "hex: " << opts.hex_string << std::endl;
std::cout << "json: " << opts.json_output << std::endl;
std::cout << "extended: " << opts.extended << std::endl;
std::cout << "shemu:" << opts.shemu << std::endl;
std::cout << "kernel:" << opts.kernel << std::endl;
std::cout << "shctx:" << opts.shctx_file << std::endl;
}
if (!_validate_and_fix_args(opts)) {
return 1;
}
if (!opts.interactive && !opts.comm) {
if (!opts.hex_string.empty() || !opts.hex_file.empty()) {
if (!_hexstring_to_bytes(opts))
return 1;
} else if (!opts.in_file.empty()) {
if (!_file_to_bytes(opts))
return 1;
}
if (opts.offset >= opts.actual_size)
return 1;
if (!opts.shemu) {
disassemble(opts);
}
else {
_load_shctx(opts);
shemu(opts);
}
} else {
while (true) {
opts.hex_string.clear();
if (!opts.comm)
std::cout << ">> ";
std::getline(std::cin, opts.hex_string);
if (opts.hex_string == "q"
|| opts.hex_string == "quit"
|| opts.hex_string == "exit"
|| opts.hex_string.empty()) {
if (!opts.comm)
std::cout << "Bye!" << std::endl;
break;
}
_hexstring_to_bytes(opts);
disassemble(opts);
std::cout.flush();
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,566 @@
/**
* License: Apache 2.0 with LLVM Exception or GPL v3
*
* Author: Jesse Laning
*/
#ifndef ARGPARSE_H
#define ARGPARSE_H
#include <algorithm>
#include <cctype>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <locale>
#include <map>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
namespace argparse {
namespace detail {
static inline bool _not_space(int ch) { return !std::isspace(ch); }
static inline void _ltrim(std::string &s, bool (*f)(int) = _not_space) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
}
static inline void _rtrim(std::string &s, bool (*f)(int) = _not_space) {
s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
}
static inline void _trim(std::string &s, bool (*f)(int) = _not_space) {
_ltrim(s, f);
_rtrim(s, f);
}
static inline std::string _ltrim_copy(std::string s,
bool (*f)(int) = _not_space) {
_ltrim(s, f);
return s;
}
static inline std::string _rtrim_copy(std::string s,
bool (*f)(int) = _not_space) {
_rtrim(s, f);
return s;
}
static inline std::string _trim_copy(std::string s,
bool (*f)(int) = _not_space) {
_trim(s, f);
return s;
}
template <typename InputIt>
static inline std::string _join(InputIt begin, InputIt end,
const std::string &separator = " ") {
std::ostringstream ss;
if (begin != end) {
ss << *begin++;
}
while (begin != end) {
ss << separator;
ss << *begin++;
}
return ss.str();
}
static inline bool _is_number(const std::string &arg) {
std::istringstream iss(arg);
float f;
iss >> std::noskipws >> f;
return iss.eof() && !iss.fail();
}
static inline int _find_equal(const std::string &s) {
for (size_t i = 0; i < s.length(); ++i) {
// if find graph symbol before equal, end search
// i.e. don't accept --asd)f=0 arguments
// but allow --asd_f and --asd-f arguments
if (std::ispunct(static_cast<int>(s[i]))) {
if (s[i] == '=') {
return static_cast<int>(i);
} else if (s[i] == '_' || s[i] == '-') {
continue;
}
return -1;
}
}
return -1;
}
static inline size_t _find_name_end(const std::string &s) {
size_t i;
for (i = 0; i < s.length(); ++i) {
if (std::ispunct(static_cast<int>(s[i]))) {
break;
}
}
return i;
}
namespace is_vector_impl {
template <typename T>
struct is_vector : std::false_type {};
template <typename... Args>
struct is_vector<std::vector<Args...>> : std::true_type {};
} // namespace is_vector_impl
// type trait to utilize the implementation type traits as well as decay the
// type
template <typename T>
struct is_vector {
static constexpr bool const value =
is_vector_impl::is_vector<typename std::decay<T>::type>::value;
};
} // namespace detail
class ArgumentParser {
private:
public:
class Argument;
class Result {
public:
Result() {}
Result(std::string err) noexcept : _error(true), _what(err) {}
operator bool() const { return _error; }
friend std::ostream &operator<<(std::ostream &os, const Result &dt);
const std::string &what() const { return _what; }
private:
bool _error{false};
std::string _what{};
};
class Argument {
public:
enum Position : int { LAST = -1, DONT_CARE = -2 };
enum Count : int { ANY = -1 };
Argument &name(const std::string &name) {
_names.push_back(name);
return *this;
}
Argument &names(std::vector<std::string> names) {
_names.insert(_names.end(), names.begin(), names.end());
return *this;
}
Argument &description(const std::string &description) {
_desc = description;
return *this;
}
Argument &required(bool req) {
_required = req;
return *this;
}
Argument &position(int position) {
if (position != Position::LAST) {
// position + 1 because technically argument zero is the name of the
// executable
_position = position + 1;
} else {
_position = position;
}
return *this;
}
Argument &count(int count) {
_count = count;
return *this;
}
bool found() const { return _found; }
template <typename T>
typename std::enable_if<detail::is_vector<T>::value, T>::type get() {
T t = T();
typename T::value_type vt;
for (auto &s : _values) {
std::istringstream in(s);
in >> vt;
t.push_back(vt);
}
return t;
}
template <typename T>
typename std::enable_if<!detail::is_vector<T>::value, T>::type get() {
std::istringstream in(get<std::string>());
T t = T();
in >> t >> std::ws;
return t;
}
private:
Argument(const std::string &name, const std::string &desc,
bool required = false)
: _desc(desc), _required(required) {
_names.push_back(name);
}
Argument() {}
friend class ArgumentParser;
int _position{Position::DONT_CARE};
int _count{Count::ANY};
std::vector<std::string> _names{};
std::string _desc{};
bool _found{false};
bool _required{false};
int _index{-1};
std::vector<std::string> _values{};
};
ArgumentParser(const std::string &bin, const std::string &desc)
: _bin(bin), _desc(desc) {}
Argument &add_argument() {
_arguments.push_back({});
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
Argument &add_argument(const std::string &name, const std::string &long_name,
const std::string &desc, const bool required = false) {
_arguments.push_back(Argument(name, desc, required));
_arguments.back()._names.push_back(long_name);
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
Argument &add_argument(const std::string &name, const std::string &desc,
const bool required = false) {
_arguments.push_back(Argument(name, desc, required));
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
void print_help(size_t count = 0, size_t page = 0) {
if (page * count > _arguments.size()) {
return;
}
if (page == 0) {
std::cout << "Usage: " << _bin;
if (_positional_arguments.empty()) {
std::cout << " [options...]" << std::endl;
} else {
int current = 1;
for (auto &v : _positional_arguments) {
if (v.first != Argument::Position::LAST) {
for (; current < v.first; current++) {
std::cout << " [" << current << "]";
}
std::cout
<< " ["
<< detail::_ltrim_copy(
_arguments[static_cast<size_t>(v.second)]._names[0],
[](int c) -> bool { return c != static_cast<int>('-'); })
<< "]";
}
}
auto it = _positional_arguments.find(Argument::Position::LAST);
if (it == _positional_arguments.end()) {
std::cout << " [options...]";
} else {
std::cout
<< " [options...] ["
<< detail::_ltrim_copy(
_arguments[static_cast<size_t>(it->second)]._names[0],
[](int c) -> bool { return c != static_cast<int>('-'); })
<< "]";
}
std::cout << std::endl;
}
std::cout << "Options:" << std::endl;
}
if (count == 0) {
page = 0;
count = _arguments.size();
}
for (size_t i = page * count;
i < std::min<size_t>(page * count + count, _arguments.size()); i++) {
Argument &a = _arguments[i];
std::string name = a._names[0];
for (size_t n = 1; n < a._names.size(); ++n) {
name.append(", " + a._names[n]);
}
std::cout << " " << std::setw(23) << std::left << name << std::setw(23)
<< a._desc;
if (a._required) {
std::cout << " (Required)";
}
std::cout << std::endl;
}
}
Result parse(int argc, const char *argv[]) {
Result err;
if (argc > 1) {
// build name map
for (auto &a : _arguments) {
for (auto &n : a._names) {
std::string name = detail::_ltrim_copy(
n, [](int c) -> bool { return c != static_cast<int>('-'); });
if (_name_map.find(name) != _name_map.end()) {
return Result("Duplicate of argument name: " + n);
}
_name_map[name] = a._index;
}
if (a._position >= 0 || a._position == Argument::Position::LAST) {
_positional_arguments[a._position] = a._index;
}
}
if (err) {
return err;
}
// parse
std::string current_arg;
size_t arg_len;
for (int argv_index = 1; argv_index < argc; ++argv_index) {
current_arg = std::string(argv[argv_index]);
arg_len = current_arg.length();
if (arg_len == 0) {
continue;
}
if (_help_enabled && (current_arg == "-h" || current_arg == "--help")) {
_arguments[static_cast<size_t>(_name_map["help"])]._found = true;
} else if (argv_index == argc - 1 &&
_positional_arguments.find(Argument::Position::LAST) !=
_positional_arguments.end()) {
err = _end_argument();
Result b = err;
err = _add_value(current_arg, Argument::Position::LAST);
if (b) {
return b;
}
if (err) {
return err;
}
} else if (arg_len >= 2 &&
!detail::_is_number(current_arg)) { // ignores the case if
// the arg is just a -
// look for -a (short) or --arg (long) args
if (current_arg[0] == '-') {
err = _end_argument();
if (err) {
return err;
}
// look for --arg (long) args
if (current_arg[1] == '-') {
err = _begin_argument(current_arg.substr(2), true, argv_index);
if (err) {
return err;
}
} else { // short args
err = _begin_argument(current_arg.substr(1), false, argv_index);
if (err) {
return err;
}
}
} else { // argument value
err = _add_value(current_arg, argv_index);
if (err) {
return err;
}
}
} else { // argument value
err = _add_value(current_arg, argv_index);
if (err) {
return err;
}
}
}
}
if (_help_enabled && exists("help")) {
return Result();
}
err = _end_argument();
if (err) {
return err;
}
for (auto &p : _positional_arguments) {
Argument &a = _arguments[static_cast<size_t>(p.second)];
if (a._values.size() > 0 && a._values[0][0] == '-') {
std::string name = detail::_ltrim_copy(a._values[0], [](int c) -> bool {
return c != static_cast<int>('-');
});
if (_name_map.find(name) != _name_map.end()) {
if (a._position == Argument::Position::LAST) {
return Result(
"Poisitional argument expected at the end, but argument " +
a._values[0] + " found instead");
} else {
return Result("Poisitional argument expected in position " +
std::to_string(a._position) + ", but argument " +
a._values[0] + " found instead");
}
}
}
}
for (auto &a : _arguments) {
if (a._required && !a._found) {
return Result("Required argument not found: " + a._names[0]);
}
if (a._position >= 0 && argc >= a._position && !a._found) {
return Result("Argument " + a._names[0] + " expected in position " +
std::to_string(a._position));
}
}
return Result();
}
void enable_help() {
add_argument("-h", "--help", "Shows this page", false);
_help_enabled = true;
}
bool exists(const std::string &name) const {
std::string n = detail::_ltrim_copy(
name, [](int c) -> bool { return c != static_cast<int>('-'); });
auto it = _name_map.find(n);
if (it != _name_map.end()) {
return _arguments[static_cast<size_t>(it->second)]._found;
}
return false;
}
template <typename T>
T get(const std::string &name) {
auto t = _name_map.find(name);
if (t != _name_map.end()) {
return _arguments[static_cast<size_t>(t->second)].get<T>();
}
return T();
}
private:
Result _begin_argument(const std::string &arg, bool longarg, int position) {
auto it = _positional_arguments.find(position);
if (it != _positional_arguments.end()) {
Result err = _end_argument();
Argument &a = _arguments[static_cast<size_t>(it->second)];
a._values.push_back((longarg ? "--" : "-") + arg);
a._found = true;
return err;
}
if (_current != -1) {
return Result("Current argument left open");
}
size_t name_end = detail::_find_name_end(arg);
std::string arg_name = arg.substr(0, name_end);
if (longarg) {
int equal_pos = detail::_find_equal(arg);
auto nmf = _name_map.find(arg_name);
if (nmf == _name_map.end()) {
return Result("Unrecognized command line option '" + arg_name + "'");
}
_current = nmf->second;
_arguments[static_cast<size_t>(nmf->second)]._found = true;
if (equal_pos == 0 ||
(equal_pos < 0 &&
arg_name.length() < arg.length())) { // malformed argument
return Result("Malformed argument: " + arg);
} else if (equal_pos > 0) {
std::string arg_value = arg.substr(name_end + 1);
_add_value(arg_value, position);
}
} else {
Result r;
if (arg_name.length() == 1) {
return _begin_argument(arg, true, position);
} else {
for (char &c : arg_name) {
r = _begin_argument(std::string(1, c), true, position);
if (r) {
return r;
}
r = _end_argument();
if (r) {
return r;
}
}
}
}
return Result();
}
Result _add_value(const std::string &value, int location) {
if (_current >= 0) {
Result err;
Argument &a = _arguments[static_cast<size_t>(_current)];
if (a._count >= 0 && static_cast<int>(a._values.size()) >= a._count) {
err = _end_argument();
if (err) {
return err;
}
goto unnamed;
}
a._values.push_back(value);
if (a._count >= 0 && static_cast<int>(a._values.size()) >= a._count) {
err = _end_argument();
if (err) {
return err;
}
}
return Result();
} else {
unnamed:
auto it = _positional_arguments.find(location);
if (it != _positional_arguments.end()) {
Argument &a = _arguments[static_cast<size_t>(it->second)];
a._values.push_back(value);
a._found = true;
}
// TODO
return Result();
}
}
Result _end_argument() {
if (_current >= 0) {
Argument &a = _arguments[static_cast<size_t>(_current)];
_current = -1;
if (static_cast<int>(a._values.size()) < a._count) {
return Result("Too few arguments given for " + a._names[0]);
}
if (a._count >= 0) {
if (static_cast<int>(a._values.size()) > a._count) {
return Result("Too many arguments given for " + a._names[0]);
}
}
}
return Result();
}
bool _help_enabled{false};
int _current{-1};
std::string _bin{};
std::string _desc{};
std::vector<Argument> _arguments{};
std::map<int, int> _positional_arguments{};
std::map<std::string, int> _name_map{};
};
std::ostream &operator<<(std::ostream &os, const ArgumentParser::Result &r) {
os << r.what();
return os;
}
template <>
inline std::string ArgumentParser::Argument::get<std::string>() {
return detail::_join(_values.begin(), _values.end());
}
template <>
inline std::vector<std::string>
ArgumentParser::Argument::get<std::vector<std::string>>() {
return _values;
}
} // namespace argparse
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,16 +0,0 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BDDISASM_VERSION_H
#define BDDISASM_VERSION_H
#define DISASM_VERSION_MAJOR 2
#define DISASM_VERSION_MINOR 1
#define DISASM_VERSION_REVISION 0
#define SHEMU_VERSION_MAJOR DISASM_VERSION_MAJOR
#define SHEMU_VERSION_MINOR DISASM_VERSION_MINOR
#define SHEMU_VERSION_REVISION DISASM_VERSION_REVISION
#endif // BDDISASM_VERSION_H

@ -7,7 +7,6 @@
#include "bddisasm.h"
#include "bdshemu_x86.h"
//
@ -15,8 +14,7 @@
//
typedef void
(*ShemuPrint)(
char *Data, // Data to be printed.
void *Context // Optional, caller-defined, context.
char *Data // Data to be printed.
);
@ -39,207 +37,185 @@ typedef ND_BOOL
);
typedef enum _SHEMU_ARCH_TYPE
// Percent of emulated instructions that must be NOP to consider a NOP sled is present.
#define SHEMU_DEFAULT_NOP_THRESHOLD 75
// Consecutive printable characters on stack to consider a stack string access.
#define SHEMU_DEFAULT_STR_THRESHOLD 8
// Will not emulate more than this number of external memory accesses. Once this threshold is exceeded, any external
// access will abort the emulation.
#define SHEMU_DEFAULT_MEM_THRESHOLD 0
//
// General purpose registers.
//
typedef struct _SHEMU_GPR_REGS
{
SHEMU_ARCH_TYPE_NONE = 0,
ND_UINT64 RegRax;
ND_UINT64 RegRcx;
ND_UINT64 RegRdx;
ND_UINT64 RegRbx;
ND_UINT64 RegRsp;
ND_UINT64 RegRbp;
ND_UINT64 RegRsi;
ND_UINT64 RegRdi;
ND_UINT64 RegR8;
ND_UINT64 RegR9;
ND_UINT64 RegR10;
ND_UINT64 RegR11;
ND_UINT64 RegR12;
ND_UINT64 RegR13;
ND_UINT64 RegR14;
ND_UINT64 RegR15;
ND_UINT64 RegCr2;
ND_UINT64 RegFlags;
ND_UINT64 RegDr7;
ND_UINT64 RegRip;
ND_UINT64 RegCr0;
ND_UINT64 RegCr4;
ND_UINT64 RegCr3;
ND_UINT64 RegCr8;
ND_UINT64 RegIdtBase;
ND_UINT64 RegIdtLimit;
ND_UINT64 RegGdtBase;
ND_UINT64 RegGdtLimit;
ND_UINT64 FpuRip;
} SHEMU_GPR_REGS, *PSHEMU_GPR_REGS;
// X86 includes both IA-32 and x86-64.
// All SHEMU flags are supported.
SHEMU_ARCH_TYPE_X86,
} SHEMU_ARCH_TYPE;
//
// Segment register (with its hidden part).
//
typedef struct _SHEMU_SEG
{
ND_UINT64 Base;
ND_UINT64 Limit;
ND_UINT64 Selector;
ND_UINT64 AccessRights;
} SHEMU_SEG, *PSHEMU_SEG;
typedef struct _SHEMU_X86_CTX
//
// The segment registers.
//
typedef struct _SHEMU_SEG_REGS
{
SHEMU_SEG Es;
SHEMU_SEG Cs;
SHEMU_SEG Ss;
SHEMU_SEG Ds;
SHEMU_SEG Fs;
SHEMU_SEG Gs;
} SHEMU_SEG_REGS, *PSHEMU_SEG_REGS;
//
// Emulation context. All of these fields must be provided as input, although most of them can be 0.
//
typedef struct _SHEMU_CONTEXT
{
// Current instruction. Doesn't have to be provided; it always contains the currently emulated instruction.
// When #ShemuEmulate returns, this will contain the last emulated instruction. In case of an emulation failure,
// it can be inspected, to gather more info about what went wrong.
INSTRUX Instruction;
INSTRUX Instruction;
// General purpose registers state. On input, the initial state. Will be updated after each emulated instruction.
SHEMU_X86_GPR_REGS Registers;
SHEMU_GPR_REGS Registers;
// Segment registers state. On input, the initial state. May be updated after some instructions.
SHEMU_X86_SEG_REGS Segments;
SHEMU_SEG_REGS Segments;
// MMX register state. 8 x 8 bytes = 64 bytes for the MMX registers. Can be provided on input, if needed.
ND_UINT64 MmxRegisters[ND_MAX_MMX_REGS];
ND_UINT64 MmxRegisters[ND_MAX_MMX_REGS];
// SSE registers state. 32 x 64 bytes = 2048 bytes for the SSE registers. Can be provided on input, if needed.
ND_UINT8 SseRegisters[ND_MAX_SSE_REGS][ND_MAX_REGISTER_SIZE];
ND_UINT8 SseRegisters[ND_MAX_SSE_REGS][ND_MAX_REGISTER_SIZE];
// General purpose registers write bitmap. After the first write, a register will be marked dirty in here.
// Should be 0 on input.
ND_UINT8 GprTracker[ND_MAX_GPR_REGS];
ND_UINT16 DirtyGprBitmap;
// Operating mode (ND_CODE_16, ND_CODE_32 or ND_CODE_64). Must be provided as input.
ND_UINT8 Mode;
ND_UINT8 Mode;
// Operating ring (0, 1, 2, 3). Must be provided as input.
ND_UINT8 Ring;
} SHEMU_X86_CTX;
ND_UINT8 Ring;
#define SHEMU_ICACHE_SIZE 0x100
typedef struct SHEMU_ICACHE
{
// Instruction cache.
ND_UINT8 Icache[SHEMU_ICACHE_SIZE];
// The first address that is cached.
ND_UINT64 Address;
// Number of valid bytes inside the cache. Maximum SHEMU_ICACHE_SIZE.
ND_UINT64 Size;
} SHEMU_ICACHE;
typedef struct SHEMU_LOOP_TRACK
{
// The address of the loop instruction. The loop instruction can be any taken conditional or unconditional
// branch that goes backwards.
ND_UINT64 Address;
// The target of the loop instructions (the first instruction of the loop).
ND_UINT64 Target;
// The current iteration number.
ND_UINT64 Iteration;
// ND_TRUE whether tracking is active, and we are inside a loop.
ND_BOOL Active;
} SHEMU_LOOP_TRACK;
//
// Emulation context. All of these fields must be provided as input, although most of them can be 0.
//
typedef struct _SHEMU_CONTEXT
{
union
{
// Used when ArchType is SHEMU_ARCH_TYPE_X86.
SHEMU_X86_CTX X86;
} Arch;
// Indicates architecture mode. Must be provided as input.
SHEMU_ARCH_TYPE ArchType;
// Instruction cache. Note that this caches instruction bytes, not decoded instructions.
SHEMU_ICACHE Icache;
// Tracks emulated loops.
SHEMU_LOOP_TRACK LoopTrack;
// The suspicious code to be emulated. Must be provided as input, as follows:
// - This buffer must be allocated by the caller, and it must be writeable. It should NOT point to process memory,
// as it will be modified by shemu in case of self-modifying code.
// - However, if the SHEMU_OPT_DIRECT_MAPPED_SHELL option is used, this field can point directly to process memory,
// but the AccessShellcode callback must also be provided. In this case, the buffer will NOT be modified by
// shemu.
ND_UINT8 *Shellcode;
// The suspicious code to be emulated. Must be provided as input.
ND_UINT8 *Shellcode;
// Virtual stack. RSP will point somewhere inside. Must be allocated as input, and it can be initialized with
// actual stack contents. Can also be 0-filled.
// This buffer must be allocated by the caller, and it must be writeable. It should not point to process memory,
// as it will be modified by shemu.
ND_UINT8 *Stack;
ND_UINT8 *Stack;
// Internal use. Must be at least the size of the shell + stack. Needs not be initialized, but must be allocated
// and accessible on input.
ND_UINT8 *Intbuf;
ND_UINT8 *Intbuf;
// Shellcode base address (the address the shellcode would see). Must be provided as input.
ND_UINT64 ShellcodeBase;
ND_UINT64 ShellcodeBase;
// Stack base address (the stack the shellcode would see). Must be provided as input.
ND_UINT64 StackBase;
// Stack base address (the RSP the shellcode would see). Must be provided as input.
ND_UINT64 StackBase;
// Shellcode size. Must be provided as input. Usually just a page in size, but can be larger.
ND_UINT64 ShellcodeSize;
ND_UINT32 ShellcodeSize;
// Stack size. Must be provided as input. Minimum two pages.
ND_UINT64 StackSize;
ND_UINT32 StackSize;
// Internal buffer size. Must be provided as input. Must be at least the size of the shell + stack.
ND_UINT64 IntbufSize;
// Number of consecutive NOPs encountered at the beginning of the code. Should be 0 on input.
ND_UINT64 NopCount;
ND_UINT32 IntbufSize;
// Number of '00 00' (ADD [rax], al) instructions encountered. Should be 0 on input.
ND_UINT64 NullCount;
// Number of NOPs encountered. Should be 0 on input.
ND_UINT32 NopCount;
// The length of the string constructed on the stack, if any. Should be 0 on input.
ND_UINT64 StrLength;
ND_UINT32 StrLength;
// Number of external memory access (outside stack/shellcode). Should be 0 on input.
ND_UINT64 ExtMemAccess;
ND_UINT32 ExtMemAccess;
// Number of emulated instructions. Should be 0 on input. Once InstructionsCount reaches MaxInstructionsCount,
// emulation will stop.
ND_UINT64 InstructionsCount;
// Number of distinct addresses executed. Will be less than or equal to InstructionsCount. In case of an infinite
// loop (JMP $), this field will be 1, but the InstructionsCount will be infinite. In case of two overlapping
// instructions, this field will be incremented twice (for example, JMP $+1).
ND_UINT64 UniqueCount;
ND_UINT32 InstructionsCount;
// Max number of instructions that should be emulated. Once this limit has been reached, emulation will stop.
// Lower values will mean faster processing, but less chances of detection. Higher values mean low performance,
// but very high chances of yielding useful results. Must be provided as input.
ND_UINT64 MaxInstructionsCount;
ND_UINT32 MaxInstructionsCount;
// Base address of the Thread Information Block (the TIB the shellcode would normally see). Must be provided as
// input.
ND_UINT64 TibBase;
ND_UINT64 TibBase;
// Shellcode Flags (see SHEMU_FLAG_*). Should be 0 on input. Will be non-zero on output if a shellcode indicator
// has been met (check SHEMU_FLAG_* values for shellcode indicators).
// Note that this field should always be checked for detection. No matter the return value of the emulator,
// if this field is non-zero, a potential shellcode has been detected. This is valid even if
// SHEMU_OPT_STOP_ON_EXPLOIT is set: this option only guarantees that emulation will not continue once a shellcode
// has been encountered, but it does not guarantee that SHEMU_ABORT_SHELLCODE_DETECTED will be returned.
ND_UINT64 Flags;
// Shellcode Flags (see SHEMU_FLAG_*). Must be provided as input.
ND_UINT64 Flags;
// Emulation options. See SHEMU_OPT_* for possible options. Must be provided as input.
ND_UINT64 Options;
ND_UINT32 Options;
// Percent of NOPs (out of total instructions emulated) that trigger NOP sled detection. Must be provided as input.
// Defaults to SHEMU_DEFAULT_NOP_THRESHOLD.
ND_UINT32 NopThreshold;
ND_UINT32 NopThreshold;
// Stack string length threshold. Stack-constructed strings must be at least this long to trigger stack string
// detection. Must be provided as input. Defaults to SHEMU_DEFAULT_STR_THRESHOLD.
ND_UINT32 StrThreshold;
// detection. Must be provided as input.
ND_UINT32 StrThreshold;
// Number of external mem accesses threshold. No more than this number of external accesses will be issued. Must
// be provided as input. Defaults to SHEMU_DEFAULT_MEM_THRESHOLD.
ND_UINT32 MemThreshold;
// be provided as input.
ND_UINT32 MemThreshold;
// Optional auxiliary data, provided by the integrator. Can be NULL, or can point to integrator specific data.
// Shemu will not use this data in any way, but callbacks that receive a SHEMU_CONTEXT pointer (such as
// #AccessMemory) can use it to reference integrator private information.
void *AuxData;
void *AuxData;
// If provided, will be used for tracing. Can be NULL.
ShemuPrint Log;
ShemuPrint Log;
// If provided, will try to access additional memory. Can be NULL.
ShemuMemAccess AccessMemory;
// Must be provided if the the SHEMU_OPT_DIRECT_MAPPED_SHELL option is used. This callback will be used to proxy
// all accesses made to the shellcode memory, including fetches, loads & stores. The AccessMemory callback is
// used only for accesses to memory that are not part of the Shellcode or the Stack.
ShemuMemAccess AccessShellcode;
// Optional context to be passed to Log. Can be NULL.
void *LogContext;
ShemuMemAccess AccessMemory;
} SHEMU_CONTEXT, *PSHEMU_CONTEXT;
@ -247,209 +223,57 @@ typedef struct _SHEMU_CONTEXT
typedef unsigned int SHEMU_STATUS;
//
// Emulation abort reasons.
//
#define SHEMU_SUCCESS 0 // Successfully emulated up to MaxInstructions.
#define SHEMU_ABORT_GLA_OUTSIDE 1 // A load or store outside the shellcode or the stack.
#define SHEMU_ABORT_RIP_OUTSIDE 2 // A part of the instruction lies outside the shellcode.
#define SHEMU_ABORT_INSTRUX_NOT_SUPPORTED 3 // An unsupported instruction was encountered.
#define SHEMU_ABORT_OPERAND_NOT_SUPPORTED 4 // An unsupported operand was encountered.
#define SHEMU_ABORT_ADDRESSING_NOT_SUPPORTED 5 // An unsupported addressing scheme used (ie, VSIB).
#define SHEMU_ABORT_GLA_OUTSIDE 1 // Address accessed outside the shellcode or stack page.
#define SHEMU_ABORT_BRANCH_OUTSIDE 2 // A branch outside the shellcode page.
#define SHEMU_ABORT_UNSUPPORTED_INSTRUX 3 // A valid but unsupported instruction was encountered.
#define SHEMU_ABORT_INVALID_INSTRUX 4 // An invalid instruction was encountered.
#define SHEMU_ABORT_ADDRESSING_UNSUPPORTED 5 // An unsupported addressing scheme used (ie, VSIB).
#define SHEMU_ABORT_REGISTER_NOT_SUPPORTED 6 // An unsupported register was used (ie, DR).
#define SHEMU_ABORT_INVALID_PARAMETER 7 // An invalid parameter was supplied.
#define SHEMU_ABORT_OP_TOO_LARGE 8 // An operand that is too large was encountered.
#define SHEMU_ABORT_NO_PRIVILEGE 9 // A privileged instruction outside kernel mode.
#define SHEMU_ABORT_CANT_EMULATE 10 // A valid, but only partially handled instruction.
#define SHEMU_ABORT_INVALID_SELECTOR 11 // An invalid selector is loaded.
#define SHEMU_ABORT_UNDEFINED 12 // Valid encoding, but undefined cominbation of bits.
#define SHEMU_ABORT_UNPREDICTABLE 13 // Instruction behavior is unpredictable.
#define SHEMU_ABORT_MISALIGNED_PC 14 // PC is not aligned to a word.
#define SHEMU_ABORT_FETCH_ERROR 15 // Could not fetch instruction bytes.
#define SHEMU_ABORT_DECODE_ERROR 16 // Could not decode the instruction.
#define SHEMU_ABORT_SHELLCODE_DETECTED 0xFFFFFFFF // Shellcode criteria met (see the shellcode flags).
// Note that this status may be returned if and only if
// the SHEMU_OPT_STOP_ON_EXPLOIT is used.
typedef enum SHEMU_FLAG_ID
{
shemuFlagIdNopSled,
shemuFlagIdLoadRip,
shemuFlagIdWriteSelf,
shemuFlagIdTebAccessPeb,
shemuFlagIdSyscall,
shemuFlagIdStackStr,
shemuFlagIdTebAccessWow32,
shemuFlagIdHeavensGate,
shemuFlagIdStackPivot,
shemuFlagIdSudAccess,
// Kernel specific flags.
shemuFlagIdKpcrAccess = 32,
shemuFlagIdSwapgs,
shemuFlagIdSyscallMsrRead,
shemuFlagIdSyscallMsrWrite,
shemuFlagIdSidt,
} SHEMU_FLAG_ID;
#define SHEMU_FLAG(id) (1ull << (id))
#define SHEMU_ABORT_SHELLCODE_DETECTED 0xFFFFFFFF // Shellcode criteria met (see the shellcode flags).
//
// Shellcode flags.
//
// General and user-mode flags.
// Long sequence of NOP instructions. Generally present before the actual shellcode. This flag will only be set if:
// 1. Minimum MaxInstructions / 2 instructions have been emulated;
// 2. Minimum NopThreshold fraction (percent) of the emulated instructions are NOPs;
// 3. No other abort condition is met during emulation.
#define SHEMU_FLAG_NOP_SLED SHEMU_FLAG(shemuFlagIdNopSled)
// The code loads RIP (CALL/POP, FNSTENV/POP, etc.). Almost always used by shellcodes in order to determine their
// position in memory. This flag will be set when the value of the instruction pointer is loaded into a general
// purpose register by any means. Techniques covered include, but are not limited to:
// 1. CALL + POP reg;
// 2. FP instruction + FNSTENV + loading the saved RIP from the saved FPU state.
// Loading the RIP via RIP relative addressing on x64 does not set this flag.
#define SHEMU_FLAG_LOAD_RIP SHEMU_FLAG(shemuFlagIdLoadRip)
// The code writes itself (decryption, unpacking, etc.). Commonly seen if the shellcode decrypts itself in memory.
// This flag will only be set if previously written data is executed. This flag will not be set if, for example,
// chunks of data are written within the shellcode but never executed.
#define SHEMU_FLAG_WRITE_SELF SHEMU_FLAG(shemuFlagIdWriteSelf)
// The code accesses the PEB field inside TEB. This is achieved via "FS:[0x30]" or "GS:[0x60]" accesses. Inside
// bdshemu, accesses to the linear address inside TEB is detected no mater how obfuscated - for example, the
// following instructions will all set this flag:
// 1. MOV eax, gs:[0x30]
// 2. MOV eax, 0x30; MOV eax, fs:[eax]
// 3. MOV eax, 0; MOV eax, fs:[eax+0x30]
#define SHEMU_FLAG_TIB_ACCESS SHEMU_FLAG(shemuFlagIdTebAccessPeb)
#define SHEMU_FLAG_TIB_ACCESS_PEB SHEMU_FLAG_TIB_ACCESS
// The code does a direct syscall/sysenter/int 0x2e|0x80. This should never happen outside the legitimate ntdll
// module. However, payloads may issue direct system calls in order to avoid detection, or to simply avoid fixing
// imports manually.
// Note that this flag will be set when the SYSCALL, SYSENTER, INT 0x2E or INT 0x80 is executed, but only if
// the EAX register contains a value that resembles a valid system call (< 0x1000).
#define SHEMU_FLAG_SYSCALL SHEMU_FLAG(shemuFlagIdSyscall)
// The code constructs & uses strings on the stack. The flag will be set only if:
// 1. The length of the string constructed on the stack is at least StrThreshold bytes long (default 8);
// 2. The constructed string is referenced by loading its address anywhere (including a register or memory).
#define SHEMU_FLAG_STACK_STR SHEMU_FLAG(shemuFlagIdStackStr)
// The code accesses the Wow32Reserved field inside TIB. This is generally used to issue system calls from Wow64.
#define SHEMU_FLAG_TIB_ACCESS_WOW32 SHEMU_FLAG(shemuFlagIdTebAccessWow32)
// The code uses Heaven's gate to switch into 64 bit mode. This can be abused by shellcodes in order to avoid
// detection by switching from legacy 32 bit mode to 64 bit mode.
#define SHEMU_FLAG_HEAVENS_GATE SHEMU_FLAG(shemuFlagIdHeavensGate)
// The code switches the stack using XCHG esp, *. This is commonly executed by a shellcode once it receives
// control after a stack pivot. By itself, this flag is FP prone, and should generally not be used alone.
// This flag will only be set if several conditions are met:
// 1. The XCHG instruction is used to load a new value in the RSP register
// 2. The new value is naturally aligned (8 bytes in 64-bit mode, 4 bytes in 32-bit mode)
// 3. The new value points either inside the shellcode or the stack area, and at least 64 bytes are valid
#define SHEMU_FLAG_STACK_PIVOT SHEMU_FLAG(shemuFlagIdStackPivot)
// The code accesses the KUSER_SHARED_DATA page. Commonly used by shellcodes which wish to issue direct system
// cals or to access various data located inside the SharedUserData page. Only accesses to the following fields
// will set this flag:
// 1. KdDebuggerEnabled (offset 0x2D4)
// 2. SystemCall (offset 0x308)
// 3. Cookie (offset 0x300)
#define SHEMU_FLAG_SUD_ACCESS SHEMU_FLAG(shemuFlagIdSudAccess)
#define SHEMU_FLAG_NOP_SLED 0x00000001 // Long sequence of NOP instructions.
#define SHEMU_FLAG_LOAD_RIP 0x00000002 // The code loads RIP (CALL/POP, FNSTENV/POP, etc.)
#define SHEMU_FLAG_WRITE_SELF 0x00000004 // The code writes itself (decryption, unpacking, etc.)
#define SHEMU_FLAG_TIB_ACCESS 0x00000008 // The code accesses the PEB field inside TIB.
#define SHEMU_FLAG_SYSCALL 0x00000010 // The code does a direct syscall/sysenter/int 0x2e|0x80.
#define SHEMU_FLAG_STACK_STR 0x00000020 // The code constructs & uses strings on the stack.
#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.
// KPCR current thread access via gs:[0x188]/fs:[0x124]. Commonly used by kernel shellcodes in order to get the
// currently exeucting thread.
#define SHEMU_FLAG_KPCR_ACCESS SHEMU_FLAG(shemuFlagIdKpcrAccess)
// SWAPGS was executed. Shellcodes may use this if they intercept a low-level event such as the SYSCALL.
#define SHEMU_FLAG_SWAPGS SHEMU_FLAG(shemuFlagIdSwapgs)
// A SYSCALL/SYSENTER MSR was read. Commonly used to locate the nt image in order to manually fix imports.
#define SHEMU_FLAG_SYSCALL_MSR_READ SHEMU_FLAG(shemuFlagIdSyscallMsrRead)
// A SYSCALL/SYSENTER MSR was written. Commonly used to intercept events such as SYSCALLs.
#define SHEMU_FLAG_SYSCALL_MSR_WRITE SHEMU_FLAG(shemuFlagIdSyscallMsrWrite)
// SIDT was executed. Commonly used to locate the nt image in order to manually fix imports.
#define SHEMU_FLAG_SIDT SHEMU_FLAG(shemuFlagIdSidt)
//
// Emulation thresholds.
//
// Percent of emulated instructions that must be NOP to consider a NOP sled is present.
#define SHEMU_DEFAULT_NOP_THRESHOLD 75
// Consecutive printable characters on stack to consider a stack string access.
#define SHEMU_DEFAULT_STR_THRESHOLD 8
// Will not emulate more than this number of external memory accesses. Once this threshold is exceeded, any external
// access will abort the emulation.
#define SHEMU_DEFAULT_MEM_THRESHOLD 0
#define SHEMU_FLAG_KPCR_ACCESS 0x00010000 // KPCR current thread access via gs:[0x188]/fs:[0x124].
#define SHEMU_FLAG_SWAPGS 0x00020000 // SWAPGS was executed.
#define SHEMU_FLAG_SYSCALL_MSR_READ 0x00040000 // A SYSCALL/SYSENTER MSR read.
#define SHEMU_FLAG_SYSCALL_MSR_WRITE 0x00080000 // A SYSCALL/SYSENTER MSR write.
#define SHEMU_FLAG_SIDT 0x00100000 // SIDT was executed.
//
// Emulation options.
//
// Trace each emulated instruction.
#define SHEMU_OPT_TRACE_EMULATION 0x0000000000000001
// When shellcode indications are confirmed, stop emulation. Note that this flag only guarantees that emulation
// will stop once we set any flag, but it does not guarantee that SHEMU_ABORT_SHELLCODE_DETECTED will be returned,
// as an emulation error may take place at any moment. Always check the Flags field of the SHEMU_CONTEXT structure
// to determine whether a detection took place or not.
#define SHEMU_OPT_STOP_ON_EXPLOIT 0x0000000000000002
// When a shellcode self-modifies, the modification will not be committed. Use this when emulating an already
// decoded shellcode, where emulating the decryption again will in fact scramble the shellcode and make it useless.
#define SHEMU_OPT_BYPASS_SELF_WRITES 0x0000000000000004
// Trace each memory access.
#define SHEMU_OPT_TRACE_MEMORY 0x0000000000000008
// Trace each identified dynamically constructed string.
#define SHEMU_OPT_TRACE_STRINGS 0x0000000000000010
// Shellcode is directly mapped, and it is not read in a dedicated buffer. No stores can be done to it. This
// allows for arbitrarly sized shellcodes to be emulated without the need to allocate separate memory & do
// copied of the target shellcode. Internally, pieces of the shellcode may still be cached.
// The size of IntBuf must be equal only to the size of the stack plus one page, and no extra memory
// needs to be allocated for the shellcode. When using this flag, the following features will not be available:
// 1. UniqueCount - it will simply indicate the total number of instructions emulated, NOT the number of unique
// instructions emulated
// 2. WRITE_SELF - self-write detection will be disabled
// Other features will work normally, as they don't require state tracking inside the IntBuf.
// When using this option, the SHEMU_OPT_BYPASS_SELF_WRITES is forced as well.
#define SHEMU_OPT_DIRECT_MAPPED_SHELL 0x0000000000000020
// Trace each identified loop.
#define SHEMU_OPT_TRACE_LOOPS 0x0000000000000080
// Indicates that AES instructions are supported, and therefore, the AES intrinsics can be used to emulate
// AES decryption.
#define SHEMU_OPT_SUPPORT_AES 0x0000000100000000
// Emulate with APX support enabled. If not provided, APX and REX2 prefixed instructions will cause emulation to
// stop.
#define SHEMU_OPT_SUPPORT_APX 0x0000000200000000
#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_BYPASS_SELF_WRITES 0x00000004 // When a shellcode self-modifies, the modification will
// not be committed. Use this when emulating an already
// decoded shellcode, where emulating the decryption again
// will in fact scramble the shellcode and make it useless.
#define SHEMU_OPT_SUPPORT_AES 0x00010000 // Indicates that AES instructions are supported, and
// therefore, the AES intrinsics can be used to emulate
// AES decryption.
//
@ -458,8 +282,6 @@ typedef enum SHEMU_FLAG_ID
#define SHEMU_INTERNAL_BUFFER_SIZE(ctx) ((ctx)->ShellcodeSize + (ctx)->StackSize)
#ifdef __cplusplus
extern "C" {
#endif
@ -467,11 +289,6 @@ extern "C" {
//
// API
//
SHEMU_STATUS
ShemuX86Emulate(
SHEMU_CONTEXT *Context
);
SHEMU_STATUS
ShemuEmulate(
SHEMU_CONTEXT *Context

@ -1,92 +0,0 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BDSHEMU_X86_
#define BDSHEMU_X86_
#include "bddisasm_types.h"
//
// General purpose registers.
//
typedef struct _SHEMU_X86_GPR_REGS
{
ND_UINT64 RegRax;
ND_UINT64 RegRcx;
ND_UINT64 RegRdx;
ND_UINT64 RegRbx;
ND_UINT64 RegRsp;
ND_UINT64 RegRbp;
ND_UINT64 RegRsi;
ND_UINT64 RegRdi;
ND_UINT64 RegR8;
ND_UINT64 RegR9;
ND_UINT64 RegR10;
ND_UINT64 RegR11;
ND_UINT64 RegR12;
ND_UINT64 RegR13;
ND_UINT64 RegR14;
ND_UINT64 RegR15;
ND_UINT64 RegR16;
ND_UINT64 RegR17;
ND_UINT64 RegR18;
ND_UINT64 RegR19;
ND_UINT64 RegR20;
ND_UINT64 RegR21;
ND_UINT64 RegR22;
ND_UINT64 RegR23;
ND_UINT64 RegR24;
ND_UINT64 RegR25;
ND_UINT64 RegR26;
ND_UINT64 RegR27;
ND_UINT64 RegR28;
ND_UINT64 RegR29;
ND_UINT64 RegR30;
ND_UINT64 RegR31;
ND_UINT64 RegCr2;
ND_UINT64 RegFlags;
ND_UINT64 RegDr7;
ND_UINT64 RegRip;
ND_UINT64 RegCr0;
ND_UINT64 RegCr4;
ND_UINT64 RegCr3;
ND_UINT64 RegCr8;
ND_UINT64 RegIdtBase;
ND_UINT64 RegIdtLimit;
ND_UINT64 RegGdtBase;
ND_UINT64 RegGdtLimit;
ND_UINT64 FpuRip;
} SHEMU_X86_GPR_REGS, *PSHEMU_X86_GPR_REGS;
ND_STATIC_ASSERT(ND_MAX_GPR_REGS <= 32, "Too many General Purpose Registers defined in bddisasm! Make sure to update SHEMU_X86_GPR_REGS!");
//
// Segment register (with its hidden part).
//
typedef struct _SHEMU_X86_SEG
{
ND_UINT64 Base;
ND_UINT64 Limit;
ND_UINT64 Selector;
ND_UINT64 AccessRights;
} SHEMU_X86_SEG, *PSHEMU_X86_SEG;
//
// The segment registers.
//
typedef struct _SHEMU_X86_SEG_REGS
{
SHEMU_X86_SEG Es;
SHEMU_X86_SEG Cs;
SHEMU_X86_SEG Ss;
SHEMU_X86_SEG Ds;
SHEMU_X86_SEG Fs;
SHEMU_X86_SEG Gs;
} SHEMU_X86_SEG_REGS, *PSHEMU_X86_SEG_REGS;
#endif

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save