v0.23
Some checks failed
vs2026-ci / win-amd64-build (debug, x64) (push) Has been cancelled
vs2026-ci / win-amd64-build (release, x64) (push) Has been cancelled
vs2026-ci / Deploy release (push) Has been cancelled

Merge pull request #670 from HyperDbg/dev
This commit is contained in:
Sina Karvandi 2026-08-03 00:04:11 +02:00 committed by GitHub
commit fa816b4062
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
131 changed files with 11814 additions and 2093 deletions

View file

@ -4,6 +4,46 @@ All notable 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/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.23.0.0] - 2026-08-03
New release of the HyperDbg Debugger.
### Added
- Added the 'ucpuid' command, thanks to [@nikzad66](https://github.com/nikzad66) ([link](https://docs.hyperdbg.org/commands/debugging-commands/ucpuid))([link](https://github.com/HyperDbg/HyperDbg/pull/658))
- Added floating-point support in the script engine ([link](https://docs.hyperdbg.org/commands/scripting-language/data-types-and-operators))([link](https://github.com/HyperDbg/HyperDbg/pull/655))
- Added new platform functions for missed CPUID wrapper ([link](https://github.com/HyperDbg/HyperDbg/commit/dd38a30d224d05bb9cfab28f6024db8cc51acffd))
- Added guards and compilation flags in CMake ([link](https://github.com/HyperDbg/HyperDbg/commit/860f736bd21a274930420a12ed7eac970732717a))
- Added SDK function for the 'ucpuid' command ([link](https://docs.hyperdbg.org/commands/debugging-commands/ucpuid))([link](https://github.com/HyperDbg/HyperDbg/pull/659))
- Added a new socket platform API and named-pipe Linux file ([link](https://github.com/HyperDbg/HyperDbg/commit/6683c2dc3db640e8b75786570759daf4e630c7f0))
- Added unix implementation of 'asm-vmx-checks.asm', and made naming convention for both files ([link](https://github.com/HyperDbg/HyperDbg/commit/7141e23aadd6cc92d7edf1259fc0a6438a96737a))
- Added the hwdbg files to the CMake files and replaced the platform files, 'RTLZeroMemory' ([link](https://github.com/HyperDbg/HyperDbg/commit/f5f822a46f5aa3041cda6f7a1c29aaf18f705f15))
- Added ucpuid to CMakeList.txt and made it portable ([link](https://github.com/HyperDbg/HyperDbg/commit/8583d99d14eed83e982df08106d8f50d04c36e6a))
- Script engine Linux build completed, and added undefined references with empty stubs for the Linux port and updated the CMake file accordingly ([link](https://github.com/HyperDbg/HyperDbg/commit/5175381c7304a268660377f3ed1c2e8860f96c55))
- Added missing files to the CMake build file and swept them for the Platform functions and guarded Windows-only code ([link](https://github.com/HyperDbg/HyperDbg/commit/4bf987a5968a65eebdbb69f514e50ee08d74aa34))
- Added stub for vendorID on the 'pci-id.cpp' file ([link](https://github.com/HyperDbg/HyperDbg/commit/600eaa47ba7bc5731c677030dea7d0562e95b97b))
- Added Linux kernel module build file (Kbuild) ([link](https://github.com/HyperDbg/HyperDbg/commit/e8650e43ac563d451c835b1a01c0241929cf3c2c))
- Added PlatformCPU Linux implementation ([link](https://github.com/HyperDbg/HyperDbg/commit/953af9388a163b9e71f48bc68966f8e670fcef27))
- Added 'vprintk' in the kernel module files for Linux ([link](https://github.com/HyperDbg/HyperDbg/commit/652721be62f759535d59fec5e603923076bc62b0))
### Changed
- Updated variable types and added float types in the script engine ([link](https://github.com/HyperDbg/HyperDbg/commit/d44c726dff91402a1f093455b69449b65657bce0))
- Porting status update and terminate thread platform call ([link](https://github.com/HyperDbg/HyperDbg/commit/a29e210ab067d4a96a0d130f61aeed5b53387565))
- Sweep and extra guards and some new platform functions ([link](https://github.com/HyperDbg/HyperDbg/commit/926070135d44b7459409e1cce1d4595426062daa))
- Fix 'UInt32' conversion for negative (signed) values ([link](https://github.com/HyperDbg/HyperDbg/commit/d4132ee7db092140b526d4cd31e445114aa470ec))
- Fix the 'snprintf_s' wrapper function for cross-platform compilation ([link](https://github.com/HyperDbg/HyperDbg/commit/aa96eaa617c0c1a432682b83a5021ac4963182d1))
- Changed 'CpuIdEx' variants to a cross-platform 'CpuCpuIdEx' ([link](https://github.com/HyperDbg/HyperDbg/commit/c13f45f8b05743c5d87d3a50687507defe54af2b))
- Updated number of CPUs to a cross-platform function ([link](https://github.com/HyperDbg/HyperDbg/commit/5fdd2e7738e6f68ed5ff516467fbc5bfdaec9759))
- Empty Linux stub for the keystone library ([link](https://github.com/HyperDbg/HyperDbg/commit/f938929a8cd8391a00c52f39dd9a129a7abf9b33))
- Build file edit for first build on 'hyperdbg-cli' ([link](https://github.com/HyperDbg/HyperDbg/commit/2024cb9374e29fbd511ba931ab8b2bf7d483457c))
- Fixed bug that made script-engine segfault, so we can type commands now ([link](https://github.com/HyperDbg/HyperDbg/commit/bdc7a150cbefbc3d85a05d2a995bad4db34fc321))
- Resync serial stream on framing overflow instead of flooding the debuggee, thanks to [@munraimix](https://github.com/munraimix) ([link](https://github.com/HyperDbg/HyperDbg/pull/663))([link](https://github.com/HyperDbg/HyperDbg/issues/661))
- Resync libhyperdbg's serial receivers on framing overflow too, thanks to [@munraimix](https://github.com/munraimix) ([link](https://github.com/HyperDbg/HyperDbg/pull/663))([link](https://github.com/HyperDbg/HyperDbg/issues/661))
- Updated Linux port documentation ([link](https://github.com/HyperDbg/HyperDbg/commit/622ea9df9730e3fe0a8ff22f035772631308ac36))
- Applied cleanup for resync serial codes ([link](https://github.com/HyperDbg/HyperDbg/commit/a24c8c0a91485132ac9e28bfb588a689c8359359))
- Fix memory-safety and robustness issues in the script engine and the PCI ID parser, thanks to [@enzo-berry](https://github.com/enzo-berry) ([link](https://github.com/HyperDbg/HyperDbg/pull/665))
### Removed
- Removed unused serial codes ([link](https://github.com/HyperDbg/HyperDbg/commit/b77df6a62bacf4bff29198b3d1acd7961a3e7f38))
## [0.22.0.0] - 2026-07-20
New release of the HyperDbg Debugger.

View file

@ -28,4 +28,5 @@ Just so you know the attributions listed on this credits page are acknowledg
- Artem Shishkin ([@honorary_bot](https://twitter.com/honorary_bot)) for always answering our hypervisor questions
- unrustled.jimmies for helping us debug and fix issues, and his contributions in HyperDbg
- Hari Mishal ([@harimishal1](https://github.com/harimishal1)) for his works on the hypertrace project for supporting Last Branch Record (LBR)
- Masoud Rahimi Jafari ([@masoudrahimi01](https://github.com/masoudrahimi01)) for his works on the hypertrace project for supporting Intel Processor Trace (PT)
- Masoud Rahimi Jafari ([@masoudrahimi01](https://github.com/masoudrahimi01)) for his works on the hypertrace project for supporting Intel Processor Trace (PT)
- Abolfazl Hassani ([@FallinBinary](https://github.com/FallinBinary)) for his contributions in HyperDbg

View file

@ -31,6 +31,23 @@ object ScriptConstants {
val SYMBOL_MEM_VALID_CHECK_MASK = 1 << 31
val INVALID = 0x80000000
val LALR_ACCEPT = 0x7fffffff
val SYMBOL_VALUE_KIND_INTEGER = 0
val SYMBOL_VALUE_KIND_FLOAT32 = 1
val SYMBOL_VALUE_KIND_FLOAT64 = 2
val SCRIPT_SCALAR_TYPE_INVALID = 0
val SCRIPT_SCALAR_TYPE_BOOL = 1
val SCRIPT_SCALAR_TYPE_I8 = 2
val SCRIPT_SCALAR_TYPE_I16 = 3
val SCRIPT_SCALAR_TYPE_I32 = 4
val SCRIPT_SCALAR_TYPE_I64 = 5
val SCRIPT_SCALAR_TYPE_U8 = 6
val SCRIPT_SCALAR_TYPE_U16 = 7
val SCRIPT_SCALAR_TYPE_U32 = 8
val SCRIPT_SCALAR_TYPE_U64 = 9
val SCRIPT_SCALAR_TYPE_F32 = 10
val SCRIPT_SCALAR_TYPE_F64 = 11
val SCRIPT_SCALAR_TYPE_POINTER = 12
val SCRIPT_SCALAR_TYPE_F80 = 13
}
/**
@ -45,6 +62,6 @@ object ScriptConstantTypes {
object ScriptEvalFunc {
object ScriptOperators extends ChiselEnum {
val sFuncUndefined, sFuncInc, sFuncDec, sFuncReference, sFuncOr, sFuncXor, sFuncAnd, sFuncAsr, sFuncAsl, sFuncAdd, sFuncSub, sFuncMul, sFuncDiv, sFuncMod, sFuncGt, sFuncLt, sFuncEgt, sFuncElt, sFuncEqual, sFuncNeq, sFuncJmp, sFuncJz, sFuncJnz, sFuncMov, sFuncStart_of_do_while, sFuncStart_of_do_while_commands, sFuncEnd_of_do_while, sFuncStart_of_for, sFuncFor_inc_dec, sFuncStart_of_for_ommands, sFuncEnd_of_if, sFuncIgnore_lvalue, sFuncPush, sFuncPop, sFuncCall, sFuncRet, sFuncPrint, sFuncFormats, sFuncEvent_enable, sFuncEvent_disable, sFuncEvent_clear, sFuncTest_statement, sFuncSpinlock_lock, sFuncSpinlock_unlock, sFuncEvent_sc, sFuncMicrosleep, sFuncPrintf, sFuncPause, sFuncFlush, sFuncEvent_trace_step, sFuncEvent_trace_step_in, sFuncEvent_trace_step_out, sFuncEvent_trace_instrumentation_step, sFuncEvent_trace_instrumentation_step_in, sFuncRdtsc, sFuncRdtscp, sFuncLbr_save, sFuncLbr_dump, sFuncLbr_print, sFuncLbr_restore, sFuncLbr_check, sFuncSpinlock_lock_custom_wait, sFuncEvent_inject, sFuncPoi, sFuncDb, sFuncDd, sFuncDw, sFuncDq, sFuncNeg, sFuncHi, sFuncLow, sFuncNot, sFuncCheck_address, sFuncDisassemble_len, sFuncDisassemble_len32, sFuncDisassemble_len64, sFuncInterlocked_increment, sFuncInterlocked_decrement, sFuncPhysical_to_virtual, sFuncVirtual_to_physical, sFuncPoi_pa, sFuncHi_pa, sFuncLow_pa, sFuncDb_pa, sFuncDd_pa, sFuncDw_pa, sFuncDq_pa, sFuncLbr_restore_by_filter, sFuncEd, sFuncEb, sFuncEq, sFuncInterlocked_exchange, sFuncInterlocked_exchange_add, sFuncEb_pa, sFuncEd_pa, sFuncEq_pa, sFuncInterlocked_compare_exchange, sFuncStrlen, sFuncStrcmp, sFuncMemcmp, sFuncStrncmp, sFuncWcslen, sFuncWcscmp, sFuncEvent_inject_error_code, sFuncMemcpy, sFuncMemcpy_pa, sFuncWcsncmp, sFuncStruct_forward_declaration, sFuncStruct_definition_begin, sFuncStruct_definition_end, sFuncStruct_variable_declaration, sFuncStruct_member_declaration, sFuncTypedef_declaration, sFuncStruct_pointer, sFuncStruct_array_dimension, sFuncStruct_declarator_complete, sFuncTyped_load, sFuncTyped_store, sFuncAggregate_copy, sFuncAggregate_zero, sFuncStruct_initializer_begin, sFuncStruct_initializer_end, sFuncStruct_pointer_cast, sFuncMember_address, sFuncMember_read, sFuncMember_dot_lvalue, sFuncMember_arrow_lvalue, sFuncMember_dot_read, sFuncMember_arrow_read = Value
val sFuncUndefined, sFuncInc, sFuncDec, sFuncReference, sFuncOr, sFuncXor, sFuncAnd, sFuncAsr, sFuncAsl, sFuncAdd, sFuncSub, sFuncMul, sFuncDiv, sFuncMod, sFuncGt, sFuncLt, sFuncEgt, sFuncElt, sFuncEqual, sFuncNeq, sFuncJmp, sFuncJz, sFuncJnz, sFuncMov, sFuncStart_of_do_while, sFuncStart_of_do_while_commands, sFuncEnd_of_do_while, sFuncStart_of_for, sFuncFor_inc_dec, sFuncStart_of_for_ommands, sFuncEnd_of_if, sFuncIgnore_lvalue, sFuncPush, sFuncPop, sFuncCall, sFuncRet, sFuncPrint, sFuncFormats, sFuncEvent_enable, sFuncEvent_disable, sFuncEvent_clear, sFuncTest_statement, sFuncSpinlock_lock, sFuncSpinlock_unlock, sFuncEvent_sc, sFuncMicrosleep, sFuncPrintf, sFuncPause, sFuncFlush, sFuncEvent_trace_step, sFuncEvent_trace_step_in, sFuncEvent_trace_step_out, sFuncEvent_trace_instrumentation_step, sFuncEvent_trace_instrumentation_step_in, sFuncRdtsc, sFuncRdtscp, sFuncLbr_save, sFuncLbr_dump, sFuncLbr_print, sFuncLbr_restore, sFuncLbr_check, sFuncSpinlock_lock_custom_wait, sFuncEvent_inject, sFuncPoi, sFuncDb, sFuncDd, sFuncDw, sFuncDq, sFuncNeg, sFuncHi, sFuncLow, sFuncNot, sFuncCheck_address, sFuncDisassemble_len, sFuncDisassemble_len32, sFuncDisassemble_len64, sFuncInterlocked_increment, sFuncInterlocked_decrement, sFuncPhysical_to_virtual, sFuncVirtual_to_physical, sFuncPoi_pa, sFuncHi_pa, sFuncLow_pa, sFuncDb_pa, sFuncDd_pa, sFuncDw_pa, sFuncDq_pa, sFuncLbr_restore_by_filter, sFuncEd, sFuncEb, sFuncEq, sFuncInterlocked_exchange, sFuncInterlocked_exchange_add, sFuncEb_pa, sFuncEd_pa, sFuncEq_pa, sFuncInterlocked_compare_exchange, sFuncStrlen, sFuncStrcmp, sFuncMemcmp, sFuncStrncmp, sFuncWcslen, sFuncWcscmp, sFuncEvent_inject_error_code, sFuncMemcpy, sFuncMemcpy_pa, sFuncWcsncmp, sFuncStruct_forward_declaration, sFuncStruct_definition_begin, sFuncStruct_definition_end, sFuncStruct_variable_declaration, sFuncStruct_member_declaration, sFuncTypedef_declaration, sFuncStruct_pointer, sFuncStruct_array_dimension, sFuncStruct_declarator_complete, sFuncTyped_load, sFuncTyped_store, sFuncAggregate_copy, sFuncAggregate_zero, sFuncStruct_initializer_begin, sFuncStruct_initializer_end, sFuncStruct_pointer_cast, sFuncMember_address, sFuncMember_read, sFuncMember_dot_lvalue, sFuncMember_arrow_lvalue, sFuncMember_dot_read, sFuncMember_arrow_read, sFuncMov_float, sFuncNeg_float, sFuncAdd_float, sFuncSub_float, sFuncMul_float, sFuncDiv_float, sFuncGt_float, sFuncLt_float, sFuncEgt_float, sFuncElt_float, sFuncEqual_float, sFuncNeq_float, sFuncConvert_float, sFuncCast_scalar, sFuncAdd_typed, sFuncSub_typed, sFuncMul_typed, sFuncDiv_typed, sFuncMod_typed, sFuncBitwise_and_typed, sFuncBitwise_or_typed, sFuncBitwise_xor_typed, sFuncShift_left_typed, sFuncShift_right_typed, sFuncGt_typed, sFuncLt_typed, sFuncEgt_typed, sFuncElt_typed, sFuncEqual_typed, sFuncNeq_typed, sFuncNeg_typed, sFuncBitwise_not_typed, sFuncLogical_not_typed, sFuncPointer_diff = Value
}
}

View file

@ -72,10 +72,34 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
#target_link_libraries(script-engine symbol-parser)
add_subdirectory(script-engine)
link_directories(libraries/zydis/user libraries/keystone/release-lib)
#link_directories(libraries/zydis/user libraries/keystone/release-lib)
add_subdirectory(libhyperdbg)
find_package(Threads REQUIRED)
target_link_libraries(libhyperdbg Zycore Zydis script-engine keystone Threads::Threads)
#target_link_libraries(libhyperdbg Zycore Zydis script-engine keystone Threads::Threads ${CMAKE_DL_LIBS})
target_link_libraries(libhyperdbg Zycore Zydis script-engine Threads::Threads ${CMAKE_DL_LIBS})
#
# Each library must define its own HYPERDBG_* macro so that the IMPORT_EXPORT_*
# annotations in include/SDK/imports/user/ resolve to the "export" form
# (visibility("default")) while it is being built, and to the "import" form in
# every other translation unit. This mirrors what the Windows .vcxproj files do
# with __declspec(dllexport)/dllimport.
#
target_compile_definitions(script-engine PRIVATE HYPERDBG_SCRIPT_ENGINE)
target_compile_definitions(libhyperdbg PRIVATE HYPERDBG_LIBHYPERDBG)
#
# The annotations above only mean something if the default visibility is hidden;
# otherwise every symbol is exported anyway and visibility("default") is a no-op.
# Hiding by default matches the Windows model (private unless dllexport-ed) and
# keeps each library's internal globals private, so same-named module-private
# globals in different libraries are no longer merged by the dynamic linker.
#
set_target_properties(script-engine libhyperdbg PROPERTIES
C_VISIBILITY_PRESET hidden
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
)
add_subdirectory(hyperdbg-cli)
target_link_libraries(hyperdbg-cli libhyperdbg)

231
hyperdbg/Kbuild Normal file
View file

@ -0,0 +1,231 @@
# SPDX-License-Identifier: GPL-3.0
#
# Kbuild for the HyperDbg Linux kernel module.
#
# This file is read by the kernel build system when it is invoked with
# M= pointing at this directory (the hyperdbg/ repo root):
#
# make -C /lib/modules/$(uname -r)/build M=<hyperdbg root> modules
#
# It is driven by linux/kernel/Makefile. kbuild prefers a file named "Kbuild"
# over "Makefile" in the M= directory, so the CMake-generated ./Makefile (which
# builds the *user-mode* CLI) is left untouched — the two build systems coexist.
#
# ---------------------------------------------------------------------------
# DESIGN
# ---------------------------------------------------------------------------
# Windows builds SEVEN separate kernel binaries (hyperkd.sys + hyperhv/hyperlog/
# hyperevade/hypertrace/hyperperf/kdserial as KMDF "export driver" DLLs that link
# against each other's import .libs). Linux has no equivalent of that idiom, so
# everything collapses into a SINGLE module: HyperDbg.ko. All the cross-module
# __declspec(dllexport/dllimport) plumbing and the DllInitialize/DllUnload unload
# trick simply disappear (one link unit, all symbols internal). kdserial is
# dropped entirely (Windows-only serial transport).
#
# Because M= is the repo root, every source the module needs already lives under
# it — no copying/symlinking, and full relative object paths mean the several
# same-named files (Common.c, DpcRoutines.c, UnloadDll.c, Broadcast.c ...) never
# collide.
#
# ---------------------------------------------------------------------------
# STATUS
# ---------------------------------------------------------------------------
# Only the objects under "ACTIVE" below actually compile as kernel code today
# (the Platform* memory/intrinsic wrappers, proven by linux/mock/kernel). Every
# other object is listed but COMMENTED OUT: the source still targets the Windows
# WDK (ntoskrnl/WDF/ntifs.h) and will not compile until its dependencies are
# routed through the platform layer. Uncomment each line as its translation unit
# is ported — the module still links and loads in the meantime.
#
# The list mirrors the .c files actually present on disk (the per-module
# CMakeLists.txt files are stale and were NOT trusted).
# ===========================================================================
obj-m += HyperDbg.o
# Include paths (union; harmless for the commented-out sources).
# linux/kernel -> the unified kernel pch.h that every `#include "pch.h"` hits
# include -> SDK/, platform/, config/, macros/, components/ roots
ccflags-y += -I$(src)/linux/kernel
ccflags-y += -I$(src)/include
ccflags-y += -I$(src)/dependencies
# Force default C dialect etc. can be added here later, e.g.:
# ccflags-y += -Wno-declaration-after-statement
#
# When the module translation units come online they all `#include "pch.h"`,
# which resolves to linux/kernel/pch.h via the -I above. If a module header dir
# that itself contains a pch.h (e.g. hyperkd/header) is ever added to ccflags,
# put it AFTER -I$(src)/linux/kernel or the wrong pch wins.
# ===========================================================================
# ACTIVE — compiles + links today
# ===========================================================================
HyperDbg-objs += linux/kernel/Entry.o
HyperDbg-objs += include/platform/kernel/code/PlatformMem.o
HyperDbg-objs += include/platform/kernel/code/PlatformIntrinsics.o
HyperDbg-objs += include/platform/kernel/code/PlatformIntrinsicsVmx.o
# ===========================================================================
# PENDING — uncomment as each is ported off the WDK
# ===========================================================================
# --- platform/kernel (OS abstraction layer) --------------------------------
HyperDbg-objs += include/platform/kernel/code/PlatformBroadcast.o
HyperDbg-objs += include/platform/kernel/code/PlatformCpu.o
HyperDbg-objs += include/platform/kernel/code/PlatformDbg.o
HyperDbg-objs += include/platform/kernel/code/PlatformDpc.o
HyperDbg-objs += include/platform/kernel/code/PlatformEvent.o
HyperDbg-objs += include/platform/kernel/code/PlatformIo.o
HyperDbg-objs += include/platform/kernel/code/PlatformIrql.o
HyperDbg-objs += include/platform/kernel/code/PlatformProcess.o
HyperDbg-objs += include/platform/kernel/code/PlatformSpinlock.o
HyperDbg-objs += include/platform/kernel/code/PlatformTime.o
# --- components (shared, header-driven) ------------------------------------
# HyperDbg-objs += include/components/spinlock/code/Spinlock.o
# HyperDbg-objs += include/components/optimizations/code/AvlTree.o
# HyperDbg-objs += include/components/optimizations/code/BinarySearch.o
# HyperDbg-objs += include/components/optimizations/code/InsertionSort.o
# HyperDbg-objs += include/components/optimizations/code/OptimizationsExamples.o
# HyperDbg-objs += include/components/callback/code/HyperLogCallback.o
# --- script-eval (script engine kernel eval) -------------------------------
# HyperDbg-objs += script-eval/code/Functions.o
# HyperDbg-objs += script-eval/code/Keywords.o
# HyperDbg-objs += script-eval/code/PseudoRegisters.o
# HyperDbg-objs += script-eval/code/Regs.o
# HyperDbg-objs += script-eval/code/ScriptEngineEval.o
# --- hyperlog (message logging/tracing) ------------------------------------
# HyperDbg-objs += hyperlog/code/Logging.o
# HyperDbg-objs += hyperlog/code/UnloadDll.o
# --- hyperhv (hypervisor: VMX/EPT) -----------------------------------------
# HyperDbg-objs += hyperhv/code/broadcast/Broadcast.o
# HyperDbg-objs += hyperhv/code/broadcast/DpcRoutines.o
# HyperDbg-objs += hyperhv/code/common/Bitwise.o
# HyperDbg-objs += hyperhv/code/common/Common.o
# HyperDbg-objs += hyperhv/code/common/UnloadDll.o
# HyperDbg-objs += hyperhv/code/components/registers/DebugRegisters.o
# HyperDbg-objs += hyperhv/code/devices/Apic.o
# HyperDbg-objs += hyperhv/code/devices/Pci.o
# HyperDbg-objs += hyperhv/code/disassembler/Disassembler.o
# HyperDbg-objs += hyperhv/code/disassembler/ZydisKernel.o
# HyperDbg-objs += hyperhv/code/features/CompatibilityChecks.o
# HyperDbg-objs += hyperhv/code/features/DirtyLogging.o
# HyperDbg-objs += hyperhv/code/globals/GlobalVariableManagement.o
# HyperDbg-objs += hyperhv/code/hooks/ept-hook/EptHook.o
# HyperDbg-objs += hyperhv/code/hooks/ept-hook/ExecTrap.o
# HyperDbg-objs += hyperhv/code/hooks/ept-hook/ModeBasedExecHook.o
# HyperDbg-objs += hyperhv/code/hooks/syscall-hook/EferHook.o
# HyperDbg-objs += hyperhv/code/hooks/syscall-hook/SyscallCallback.o
# HyperDbg-objs += hyperhv/code/interface/Callback.o
# HyperDbg-objs += hyperhv/code/interface/Configuration.o
# HyperDbg-objs += hyperhv/code/interface/DirectVmcall.o
# HyperDbg-objs += hyperhv/code/interface/Dispatch.o
# HyperDbg-objs += hyperhv/code/interface/Export.o
# HyperDbg-objs += hyperhv/code/interface/HyperEvade.o
# HyperDbg-objs += hyperhv/code/memory/AddressCheck.o
# HyperDbg-objs += hyperhv/code/memory/Conversion.o
# HyperDbg-objs += hyperhv/code/memory/Layout.o
# HyperDbg-objs += hyperhv/code/memory/MemoryManager.o
# HyperDbg-objs += hyperhv/code/memory/MemoryMapper.o
# HyperDbg-objs += hyperhv/code/memory/Segmentation.o
# HyperDbg-objs += hyperhv/code/memory/SwitchLayout.o
# HyperDbg-objs += hyperhv/code/mmio/MmioShadowing.o
# HyperDbg-objs += hyperhv/code/processor/Idt.o
# HyperDbg-objs += hyperhv/code/processor/Smm.o
# HyperDbg-objs += hyperhv/code/vmm/ept/Ept.o
# HyperDbg-objs += hyperhv/code/vmm/ept/Invept.o
# HyperDbg-objs += hyperhv/code/vmm/ept/Vpid.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/Counters.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/CrossVmcalls.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/CrossVmexits.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/Events.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/Hv.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/IdtEmulation.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/IoHandler.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/ManageRegs.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/MsrHandlers.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/Mtf.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/ProtectedHv.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/Vmcall.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/Vmexit.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/Vmx.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/VmxBroadcast.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/VmxMechanisms.o
# HyperDbg-objs += hyperhv/code/vmm/vmx/VmxRegions.o
# hyperhv assembly (MASM -> GAS/.S translation required; not just a build change)
# HyperDbg-objs += hyperhv/code/assembly/AsmCommon.o
# HyperDbg-objs += hyperhv/code/assembly/AsmEpt.o
# HyperDbg-objs += hyperhv/code/assembly/AsmHooks.o
# HyperDbg-objs += hyperhv/code/assembly/AsmInterruptHandlers.o
# HyperDbg-objs += hyperhv/code/assembly/AsmSegmentRegs.o
# HyperDbg-objs += hyperhv/code/assembly/AsmVmexitHandler.o
# HyperDbg-objs += hyperhv/code/assembly/AsmVmxContextState.o
# HyperDbg-objs += hyperhv/code/assembly/AsmVmxOperation.o
# --- hyperkd (the driver: device/IOCTL + debugger core) --------------------
# HyperDbg-objs += hyperkd/code/common/Common.o
# HyperDbg-objs += hyperkd/code/common/Synchronization.o
# HyperDbg-objs += hyperkd/code/debugger/broadcast/DpcRoutines.o
# HyperDbg-objs += hyperkd/code/debugger/broadcast/HaltedBroadcast.o
# HyperDbg-objs += hyperkd/code/debugger/broadcast/HaltedRoutines.o
# HyperDbg-objs += hyperkd/code/debugger/commands/BreakpointCommands.o
# HyperDbg-objs += hyperkd/code/debugger/commands/Callstack.o
# HyperDbg-objs += hyperkd/code/debugger/commands/DebuggerCommands.o
# HyperDbg-objs += hyperkd/code/debugger/commands/ExtensionCommands.o
# HyperDbg-objs += hyperkd/code/debugger/communication/SerialConnection.o
# HyperDbg-objs += hyperkd/code/debugger/core/Debugger.o
# HyperDbg-objs += hyperkd/code/debugger/core/DebuggerVmcalls.o
# HyperDbg-objs += hyperkd/code/debugger/core/HaltedCore.o
# HyperDbg-objs += hyperkd/code/debugger/events/ApplyEvents.o
# HyperDbg-objs += hyperkd/code/debugger/events/DebuggerEvents.o
# HyperDbg-objs += hyperkd/code/debugger/events/Termination.o
# HyperDbg-objs += hyperkd/code/debugger/events/ValidateEvents.o
# HyperDbg-objs += hyperkd/code/debugger/kernel-level/Kd.o
# HyperDbg-objs += hyperkd/code/debugger/memory/Allocations.o
# HyperDbg-objs += hyperkd/code/debugger/memory/PoolManager.o
# HyperDbg-objs += hyperkd/code/debugger/meta-events/MetaDispatch.o
# HyperDbg-objs += hyperkd/code/debugger/meta-events/Tracing.o
# HyperDbg-objs += hyperkd/code/debugger/objects/Process.o
# HyperDbg-objs += hyperkd/code/debugger/objects/Thread.o
# HyperDbg-objs += hyperkd/code/debugger/script-engine/ScriptEngine.o
# HyperDbg-objs += hyperkd/code/debugger/tests/KernelTests.o
# HyperDbg-objs += hyperkd/code/debugger/user-level/Attaching.o
# HyperDbg-objs += hyperkd/code/debugger/user-level/ThreadHolder.o
# HyperDbg-objs += hyperkd/code/debugger/user-level/Ud.o
# HyperDbg-objs += hyperkd/code/debugger/user-level/UserAccess.o
# HyperDbg-objs += hyperkd/code/driver/Driver.o
# HyperDbg-objs += hyperkd/code/driver/Ioctl.o
# HyperDbg-objs += hyperkd/code/driver/Loader.o
# hyperkd assembly (MASM -> GAS/.S translation required)
# HyperDbg-objs += hyperkd/code/assembly/AsmDebugger.o
# --- hyperevade (transparency / anti-detection) ----------------------------
# HyperDbg-objs += hyperevade/code/SyscallFootprints.o
# HyperDbg-objs += hyperevade/code/Transparency.o
# HyperDbg-objs += hyperevade/code/UnloadDll.o
# HyperDbg-objs += hyperevade/code/VmxFootprints.o
# --- hyperperf (PMU) -------------------------------------------------------
# HyperDbg-objs += hyperperf/code/api/PerfApi.o
# HyperDbg-objs += hyperperf/code/broadcast/Broadcast.o
# HyperDbg-objs += hyperperf/code/broadcast/DpcRoutines.o
# HyperDbg-objs += hyperperf/code/common/UnloadDll.o
# --- hypertrace (LBR / Intel PT) -------------------------------------------
# HyperDbg-objs += hypertrace/code/api/LbrApi.o
# HyperDbg-objs += hypertrace/code/api/PtApi.o
# HyperDbg-objs += hypertrace/code/api/TraceApi.o
# HyperDbg-objs += hypertrace/code/broadcast/Broadcast.o
# HyperDbg-objs += hypertrace/code/broadcast/DpcRoutines.o
# HyperDbg-objs += hypertrace/code/common/UnloadDll.o
# HyperDbg-objs += hypertrace/code/lbr/Lbr.o
# HyperDbg-objs += hypertrace/code/pt/Pt.o
# --- zydis (kernel disassembler, needed by hyperhv/disassembler) -----------
# Built with ZYAN_NO_LIBC;ZYDIS_NO_LIBC;ZYDIS_STATIC_BUILD;ZYCORE_STATIC_BUILD.
# Enumerate dependencies/zydis/src/*.c + dependencies/zydis/.../zycore/*.c here,
# or build them into a built-in.a. Deferred until hyperhv compiles.

View file

@ -21,6 +21,8 @@
int
main(int argc, char * argv[])
{
BOOLEAN TestResult = FALSE;
if (argc != 2)
{
printf("you should not test functionalities directly, instead use 'test all' "
@ -37,6 +39,7 @@ main(int argc, char * argv[])
if (TestCommandParser())
{
printf("\n[*] The main command parser test cases passed successfully\n");
TestResult = TRUE;
}
else
{
@ -52,6 +55,7 @@ main(int argc, char * argv[])
if (TestPeParser())
{
printf("\n[*] The PE parser test cases passed successfully\n");
TestResult = TRUE;
}
else
{
@ -67,6 +71,7 @@ main(int argc, char * argv[])
if (TestSemanticScripts())
{
printf("\n[*] The script semantic test cases passed successfully\n");
TestResult = TRUE;
}
else
{
@ -82,6 +87,7 @@ main(int argc, char * argv[])
if (TestCodeViewRsdsParser())
{
printf("\n[*] The CodeView RSDS parser test cases passed successfully\n");
TestResult = TRUE;
}
else
{
@ -96,20 +102,42 @@ main(int argc, char * argv[])
if (HwdbgTestCreateTestCases())
{
printf("\n[*] The hwdbg test cases passed successfully\n");
TestResult = TRUE;
}
else
{
printf("\n[x] The hwdbg test cases failed\n");
}
}
else if (!strcmp(argv[1], TEST_CASE_PARAMETER_FOR_SCRIPT_FLOATING_POINT))
{
if (TestScriptEngineFloatingPoint())
{
printf("\n[*] The script floating-point test cases passed successfully\n");
TestResult = TRUE;
}
else
{
printf("\n[x] The script floating-point test cases failed\n");
}
}
else if (!strcmp(argv[1], TEST_CASE_PARAMETER_FOR_SCRIPT_VARIABLE_TYPES))
{
if (TestScriptEngineVariableTypes())
{
printf("\n[*] The script variable-type test cases passed successfully\n");
TestResult = TRUE;
}
else
{
printf("\n[x] The script variable-type test cases failed\n");
}
}
else
{
printf("unknown test case\n");
return 1;
}
printf("\npress any key to exit...");
_getch();
return 0;
return TestResult ? 0 : 1;
}

View file

@ -0,0 +1,271 @@
/**
* @file test-script-floating-point.cpp
* @brief Focused scanner, IR, evaluator, and formatting tests for floating-point scripts.
*/
#include "pch.h"
static std::string CapturedScriptOutput;
static VOID
CaptureScriptOutput(CHAR * Message)
{
if (Message)
{
CapturedScriptOutput.append(Message);
}
}
static BOOLEAN
RunScriptAndExpect(const CHAR * Script, BOOLEAN ExpectedSuccess, const CHAR * ExpectedOutput)
{
CapturedScriptOutput.clear();
hyperdbg_u_set_text_message_callback((PVOID)CaptureScriptOutput);
BOOLEAN Result = hyperdbg_u_test_script_engine((CHAR *)Script);
hyperdbg_u_unset_text_message_callback();
if (Result != ExpectedSuccess)
{
std::cerr << "Unexpected script result for: " << Script
<< "\nExpected success: " << (ExpectedSuccess ? "true" : "false")
<< "\nActual output: " << CapturedScriptOutput << std::endl;
return FALSE;
}
if (ExpectedOutput && CapturedScriptOutput != ExpectedOutput)
{
std::cerr << "Unexpected script output for: " << Script
<< "\nExpected: " << ExpectedOutput
<< "\nActual: " << CapturedScriptOutput << std::endl;
return FALSE;
}
return TRUE;
}
static BOOLEAN
RunScriptAndExpectRuntimeFailure(const CHAR * Script)
{
if (!RunScriptAndExpect(Script, FALSE, NULL)) return FALSE;
if (CapturedScriptOutput.find("ScriptEngineExecute") == std::string::npos)
{
std::cerr << "Expected an evaluator failure for: " << Script
<< "\nActual output: " << CapturedScriptOutput << std::endl;
return FALSE;
}
return TRUE;
}
static BOOLEAN
TestFloatingPointIr()
{
if (sizeof(SYMBOL) != sizeof(UINT64) * 3 ||
FUNC_MEMBER_ARROW_READ != 128 || FUNC_MOV_FLOAT != 129 || FUNC_NEG_FLOAT != 130 ||
FUNC_ADD_FLOAT != 131 || FUNC_SUB_FLOAT != 132 || FUNC_MUL_FLOAT != 133 ||
FUNC_DIV_FLOAT != 134 || FUNC_GT_FLOAT != 135 || FUNC_LT_FLOAT != 136 ||
FUNC_EGT_FLOAT != 137 || FUNC_ELT_FLOAT != 138 || FUNC_EQUAL_FLOAT != 139 ||
FUNC_NEQ_FLOAT != 140 || FUNC_CONVERT_FLOAT != 141)
{
return FALSE;
}
CHAR Script[] = "{ float single = 11.5; double wide = 0.789; double negativeZero = -0.0; }";
PSYMBOL_BUFFER Buffer = (PSYMBOL_BUFFER)ScriptEngineParse(Script);
if (!Buffer || Buffer->Message)
{
if (Buffer)
{
RemoveSymbolBuffer(Buffer);
}
return FALSE;
}
UINT32 MoveCount = 0;
BOOLEAN FloatBitsFound = FALSE;
BOOLEAN DoubleBitsFound = FALSE;
BOOLEAN NegativeZeroFound = FALSE;
for (UINT32 Index = 0; Index + 2 < Buffer->Pointer; Index++)
{
PSYMBOL Operator = Buffer->Head + Index;
if (Operator->Type != SYMBOL_SEMANTIC_RULE_TYPE || Operator->Value != FUNC_MOV_FLOAT)
{
continue;
}
PSYMBOL Source = Buffer->Head + Index + 1;
PSYMBOL Destination = Buffer->Head + Index + 2;
MoveCount++;
if (Source->Len != Destination->Len)
{
RemoveSymbolBuffer(Buffer);
return FALSE;
}
FloatBitsFound |= Source->Len == SYMBOL_VALUE_KIND_FLOAT32 && Source->Value == 0x41380000ULL;
DoubleBitsFound |= Source->Len == SYMBOL_VALUE_KIND_FLOAT64 && Source->Value == 0x3fe93f7ced916873ULL;
NegativeZeroFound |= Source->Len == SYMBOL_VALUE_KIND_FLOAT64 && Source->Value == 0x8000000000000000ULL;
}
RemoveSymbolBuffer(Buffer);
return MoveCount == 3 && FloatBitsFound && DoubleBitsFound && NegativeZeroFound;
}
static BOOLEAN
TestFloatingPointArithmeticIr()
{
CHAR Script[] =
"{ float leftValue = 1.5; float rightValue = 0.5; "
"float addResult = leftValue + rightValue; float subResult = leftValue - rightValue; "
"float mulResult = leftValue * rightValue; float divResult = leftValue / rightValue; "
"if (addResult > subResult && addResult >= subResult && subResult < addResult && "
"subResult <= addResult && addResult == addResult && addResult != subResult) { printf(\"ok\\n\"); } }";
PSYMBOL_BUFFER Buffer = (PSYMBOL_BUFFER)ScriptEngineParse(Script);
if (!Buffer || Buffer->Message)
{
if (Buffer) RemoveSymbolBuffer(Buffer);
return FALSE;
}
BOOLEAN Seen[10] = {0};
for (UINT32 Index = 0; Index < Buffer->Pointer; Index++)
{
PSYMBOL Symbol = Buffer->Head + Index;
if (Symbol->Type != SYMBOL_SEMANTIC_RULE_TYPE ||
Symbol->Value < FUNC_ADD_FLOAT || Symbol->Value > FUNC_NEQ_FLOAT)
{
continue;
}
UINT32 OpcodeIndex = (UINT32)(Symbol->Value - FUNC_ADD_FLOAT);
Seen[OpcodeIndex] = TRUE;
if (Index + 3 >= Buffer->Pointer ||
Buffer->Head[Index + 1].Len != SYMBOL_VALUE_KIND_FLOAT32 ||
Buffer->Head[Index + 2].Len != SYMBOL_VALUE_KIND_FLOAT32)
{
RemoveSymbolBuffer(Buffer);
return FALSE;
}
BOOLEAN IsComparison = Symbol->Value >= FUNC_GT_FLOAT;
if (Buffer->Head[Index + 3].Len !=
(IsComparison ? SYMBOL_VALUE_KIND_INTEGER : SYMBOL_VALUE_KIND_FLOAT32))
{
RemoveSymbolBuffer(Buffer);
return FALSE;
}
}
RemoveSymbolBuffer(Buffer);
for (UINT32 Index = 0; Index < 10; Index++)
{
if (!Seen[Index]) return FALSE;
}
return TRUE;
}
static BOOLEAN
TestFloatingPointDifferentialCases()
{
struct OPERANDS
{
double Left;
double Right;
} Cases[] = {
{0.1, 0.2}, {1.5, 0.5}, {-4.25, 2.5}, {7.0, 3.0},
{31.75, -0.125}, {-9.5, -2.25}, {0.000125, 64.0}, {999.0, 0.75}};
const CHAR Operators[] = {'+', '-', '*', '/'};
for (const auto & Case : Cases)
{
for (CHAR Operator : Operators)
{
volatile double DoubleLeft = Case.Left;
volatile double DoubleRight = Case.Right;
double DoubleExpected;
if (Operator == '+') DoubleExpected = DoubleLeft + DoubleRight;
else if (Operator == '-') DoubleExpected = DoubleLeft - DoubleRight;
else if (Operator == '*') DoubleExpected = DoubleLeft * DoubleRight;
else DoubleExpected = DoubleLeft / DoubleRight;
CHAR Script[1024];
_snprintf_s(Script,
sizeof(Script),
_TRUNCATE,
"{ double leftValue = %.20f; double rightValue = %.20f; "
"double expectedValue = %.20f; double actualValue = leftValue %c rightValue; "
"if (actualValue == expectedValue) { printf(\"ok\\n\"); } }",
Case.Left,
Case.Right,
DoubleExpected,
Operator);
if (!RunScriptAndExpect(Script, TRUE, "ok\n")) return FALSE;
volatile float FloatLeft = (float)Case.Left;
volatile float FloatRight = (float)Case.Right;
float FloatExpected;
if (Operator == '+') FloatExpected = FloatLeft + FloatRight;
else if (Operator == '-') FloatExpected = FloatLeft - FloatRight;
else if (Operator == '*') FloatExpected = FloatLeft * FloatRight;
else FloatExpected = FloatLeft / FloatRight;
_snprintf_s(Script,
sizeof(Script),
_TRUNCATE,
"{ float leftValue = %.20f; float rightValue = %.20f; "
"float expectedValue = %.20f; float actualValue = leftValue %c rightValue; "
"if (actualValue == expectedValue) { printf(\"ok\\n\"); } }",
(double)FloatLeft,
(double)FloatRight,
(double)FloatExpected,
Operator);
if (!RunScriptAndExpect(Script, TRUE, "ok\n")) return FALSE;
}
}
return TRUE;
}
BOOLEAN
TestScriptEngineFloatingPoint()
{
const CHAR * ValidScript =
"{ float varA = 11.5; float varB = .5; double varC = 0.789; double varZ = -0.0; double varP = +.5; "
"printf(\"%f %f %f %f %f\\n\", varA, varB, varC, varZ, varP); printf(\"%f\\n\", -varC); }";
if (!RunScriptAndExpect(ValidScript,
TRUE,
"11.500000 0.500000 0.789000 -0.000000 0.500000\n-0.789000\n"))
{
return FALSE;
}
if (!TestFloatingPointIr() || !TestFloatingPointArithmeticIr() ||
!TestFloatingPointDifferentialCases() ||
!RunScriptAndExpect("{ float var1 = 11.5; float var2 = 0.5; float result = var1 + var2; if (result == 12.0) { printf(\"arithmetic ok\\n\"); } }",
TRUE,
"arithmetic ok\n") ||
!RunScriptAndExpect("{ double leftValue = 9.0; double rightValue = 4.0; double result = leftValue / rightValue; if (result >= 2.25 && result <= 2.25) { printf(\"comparison ok\\n\"); } }",
TRUE,
"comparison ok\n") ||
!RunScriptAndExpect("{ float pointOne = 0.1; float pointTwo = 0.2; float expectedFloat = 0.3; float roundedFloat = pointOne + pointTwo; double third = 1.0 / 3.0; double expectedThird = 0.33333333333333331; double largeValue = 9007199254740992.0; double oneValue = 1.0; double roundedLarge = largeValue + oneValue; double negativeValue = -4.0; double positiveValue = 2.0; double negativeZeroValue = -0.0 * positiveValue; if (roundedFloat == expectedFloat && third == expectedThird && roundedLarge == largeValue && negativeValue < positiveValue && negativeValue <= positiveValue && positiveValue > negativeValue && positiveValue >= negativeValue && negativeZeroValue == 0.0) { printf(\"rounding and comparison ok %f\\n\", negativeZeroValue); } }",
TRUE,
"rounding and comparison ok -0.000000\n") ||
!RunScriptAndExpect("{ float tinyValue = 0.000000000000000000000000000000000000000000001401298464324817; float expectedTinySum = 0.000000000000000000000000000000000000000000002802596928649634; float tinySum = tinyValue + tinyValue; if (tinySum == expectedTinySum) { printf(\"subnormal ok\\n\"); } }",
TRUE,
"subnormal ok\n") ||
!RunScriptAndExpect("{ printf(\"%f\", 1); }", FALSE, NULL) ||
!RunScriptAndExpect("{ double value = 1.5; printf(\"%x\", value); }", FALSE, NULL) ||
!RunScriptAndExpect("{ double value = 1..2; }", FALSE, NULL) ||
!RunScriptAndExpect("{ double value = 0x1.2; }", FALSE, NULL) ||
!RunScriptAndExpect("{ double value = 1.0f; }", FALSE, NULL) ||
!RunScriptAndExpect("{ float value = 999999999999999999999999999999999999999.0; }", FALSE, NULL) ||
!RunScriptAndExpect("{ float value = 0.000000000000000000000000000000000000000000000000001; }", FALSE, NULL) ||
!RunScriptAndExpectRuntimeFailure("{ double leftValue = 1.0; double zeroValue = 0.0; double result = leftValue / zeroValue; }") ||
!RunScriptAndExpectRuntimeFailure("{ double largeValue = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.0; double result = largeValue * largeValue; }"))
{
return FALSE;
}
return TRUE;
}

View file

@ -0,0 +1,163 @@
/**
* @file test-script-variable-types.cpp
* @brief Focused parser, IR, and evaluator tests for scalar variable types.
*/
#include "pch.h"
static std::string CapturedVariableTypeOutput;
static VOID
CaptureVariableTypeOutput(CHAR * Message)
{
if (Message)
CapturedVariableTypeOutput.append(Message);
}
static BOOLEAN
RunVariableTypeScript(const CHAR * Script, const CHAR * ExpectedOutput)
{
CapturedVariableTypeOutput.clear();
hyperdbg_u_set_text_message_callback((PVOID)CaptureVariableTypeOutput);
BOOLEAN Result = hyperdbg_u_test_script_engine((CHAR *)Script);
hyperdbg_u_unset_text_message_callback();
if (!Result || CapturedVariableTypeOutput != ExpectedOutput)
{
std::cerr << "Variable-type script failed: " << Script
<< "\nExpected: " << ExpectedOutput
<< "\nActual: " << CapturedVariableTypeOutput << std::endl;
PSYMBOL_BUFFER Buffer = (PSYMBOL_BUFFER)ScriptEngineParse((CHAR *)Script);
if (Buffer && !Buffer->Message)
{
for (UINT32 Index = 0; Index < Buffer->Pointer; Index++)
{
std::cerr << Index << ": type=" << Buffer->Head[Index].Type
<< " len=" << Buffer->Head[Index].Len
<< " value=" << Buffer->Head[Index].Value << std::endl;
}
}
if (Buffer) RemoveSymbolBuffer(Buffer);
return FALSE;
}
return TRUE;
}
static BOOLEAN
RunVariableTypeScriptExpectFailure(const CHAR * Script)
{
CapturedVariableTypeOutput.clear();
hyperdbg_u_set_text_message_callback((PVOID)CaptureVariableTypeOutput);
BOOLEAN Result = hyperdbg_u_test_script_engine((CHAR *)Script);
hyperdbg_u_unset_text_message_callback();
if (Result)
{
std::cerr << "Variable-type script unexpectedly succeeded: " << Script << std::endl;
return FALSE;
}
return TRUE;
}
static BOOLEAN
TestVariableTypeIrContract()
{
if (sizeof(SYMBOL) != sizeof(UINT64) * 3 ||
FUNC_CONVERT_FLOAT != 141 || FUNC_CAST_SCALAR != 142 ||
FUNC_ADD_TYPED != 143 || FUNC_NEQ_TYPED != 158 ||
FUNC_NEG_TYPED != 159 || FUNC_BITWISE_NOT_TYPED != 160 ||
FUNC_LOGICAL_NOT_TYPED != 161 || FUNC_POINTER_DIFF != 162 ||
SCRIPT_SCALAR_TYPE_INVALID != 0 || SCRIPT_SCALAR_TYPE_BOOL != 1 ||
SCRIPT_SCALAR_TYPE_I8 != 2 || SCRIPT_SCALAR_TYPE_I16 != 3 ||
SCRIPT_SCALAR_TYPE_I32 != 4 || SCRIPT_SCALAR_TYPE_I64 != 5 ||
SCRIPT_SCALAR_TYPE_U8 != 6 || SCRIPT_SCALAR_TYPE_U16 != 7 ||
SCRIPT_SCALAR_TYPE_U32 != 8 || SCRIPT_SCALAR_TYPE_U64 != 9 ||
SCRIPT_SCALAR_TYPE_F32 != 10 || SCRIPT_SCALAR_TYPE_F64 != 11 ||
SCRIPT_SCALAR_TYPE_POINTER != 12 || SCRIPT_SCALAR_TYPE_F80 != 13)
{
std::cerr << "Variable-type serialized IR constants changed unexpectedly" << std::endl;
return FALSE;
}
CHAR Script[] = "{ unsigned char narrowValue = 0x12345; int value = narrowValue + 1; value %= 4; }";
PSYMBOL_BUFFER Buffer = (PSYMBOL_BUFFER)ScriptEngineParse(Script);
if (!Buffer || Buffer->Message)
{
std::cerr << "Variable-type IR script did not parse: "
<< (Buffer && Buffer->Message ? Buffer->Message : "no buffer") << std::endl;
if (Buffer) RemoveSymbolBuffer(Buffer);
return FALSE;
}
BOOLEAN SawCast = FALSE;
BOOLEAN SawAdd = FALSE;
BOOLEAN SawModulo = FALSE;
for (UINT32 Index = 0; Index < Buffer->Pointer; Index++)
{
if (Buffer->Head[Index].Type != SYMBOL_SEMANTIC_RULE_TYPE)
continue;
SawCast |= Buffer->Head[Index].Value == FUNC_CAST_SCALAR;
SawAdd |= Buffer->Head[Index].Value == FUNC_ADD_TYPED;
SawModulo |= Buffer->Head[Index].Value == FUNC_MOD_TYPED;
}
RemoveSymbolBuffer(Buffer);
if (!SawCast || !SawAdd || !SawModulo)
{
std::cerr << "Variable-type IR is missing cast/add/modulo: "
<< SawCast << "/" << SawAdd << "/" << SawModulo << std::endl;
}
return SawCast && SawAdd && SawModulo;
}
BOOLEAN
TestScriptEngineVariableTypes()
{
return TestVariableTypeIrContract() &&
RunVariableTypeScript("{ char narrow = 0xff; unsigned char narrowValue = 0x12345; int promoted = narrowValue; printf(\"%lld %lld %lld\\n\", narrow, narrowValue, promoted); }",
"-1 69 69\n") &&
RunVariableTypeScript("{ int value = 0n10; value %= 4; long wide = 0n10; wide %= 4; printf(\"%lld %lld\\n\", value, wide); }",
"2 2\n") &&
RunVariableTypeScript("{ printf(\"%lld %lld %lld %lld %lld\\n\", sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(long long)); }",
"1 2 4 8 8\n") &&
RunVariableTypeScript("{ printf(\"%lld %lld\\n\", sizeof(!(char)0), sizeof(!(long)0)); }",
"4 4\n") &&
RunVariableTypeScript("{ if (sizeof(char) == 1 && (int)1 == 1) { printf(\"boolean type syntax\\n\"); } }",
"boolean type syntax\n") &&
RunVariableTypeScript("{ struct Pair { int left; unsigned short right; }; printf(\"%lld\\n\", sizeof(struct Pair)); }",
"8\n") &&
RunVariableTypeScript("{ struct NarrowFields { char signedValue; unsigned char unsignedValue; }; struct NarrowFields fields; fields.signedValue = 0xff; fields.unsignedValue = 0x1ff; printf(\"%lld %lld\\n\", fields.signedValue, fields.unsignedValue); }",
"-1 255\n") &&
RunVariableTypeScript("{ struct CompoundFields { int signedValue; unsigned char unsignedValue; }; struct CompoundFields fields; fields.signedValue = 0n10; fields.signedValue %= 4; fields.unsignedValue = 0x105; fields.unsignedValue += 0x100; printf(\"%lld %lld\\n\", fields.signedValue, fields.unsignedValue); }",
"2 5\n") &&
RunVariableTypeScript("{ char values[2] = {0xff, 0x7f}; printf(\"%lld %lld\\n\", values[0], values[1]); }",
"-1 127\n") &&
RunVariableTypeScript("{ typedef unsigned short word; word value = 0x12345; printf(\"%lld %lld\\n\", value, sizeof(word)); }",
"9029 2\n") &&
RunVariableTypeScript("{ int probe() { printf(\"evaluated\\n\"); return 1; } printf(\"%lld\\n\", sizeof(probe())); }",
"4\n") &&
RunVariableTypeScript("{ int add_to_55(int value) { return 0n55 + value; } result = add_to_55(0n47); printf(\"%lld\\n\", result); }",
"102\n") &&
RunVariableTypeScript("{ int typed_factorial(int value) { if (value == 0 || value == 1) { return 1; } return value * typed_factorial(value - 1); } result = typed_factorial(0n10); printf(\"%lld\\n\", result); }",
"3628800\n") &&
RunVariableTypeScript("{ source_value = 0n123456; destination_value = 0; memcpy(&destination_value, &source_value, 8); printf(\"%lld\\n\", destination_value); }",
"123456\n") &&
RunVariableTypeScript("{ local_value = 0n55; result = &local_value; printf(\"%lld %lld\\n\", sizeof(result), dq(result)); }",
"8 55\n") &&
RunVariableTypeScript("{ .global_value = 0n55; result = &(.global_value); printf(\"%lld %lld\\n\", sizeof(result), dq(result)); }",
"8 55\n") &&
RunVariableTypeScript("{ char narrow_value = 0x7f; char *narrow_pointer = &narrow_value; printf(\"%lld\\n\", *narrow_pointer); }",
"127\n") &&
RunVariableTypeScript("{ int integerValue = (int)(unsigned char)0x12345; double doubleValue = (double)integerValue; long restored = (long)doubleValue; printf(\"%lld %f %lld\\n\", integerValue, doubleValue, restored); }",
"69 69.000000 69\n") &&
RunVariableTypeScript("{ char *left = (char *)0xffffffffffffffff; char *right = (char *)0xfffffffffffffff0; if (left > right) { printf(\"%lld %lld 1\\n\", left - right, right - left); } }",
"15 -15 1\n") &&
RunVariableTypeScript("{ char *base = (char *)0x1000; char *next = base + 0n2; printf(\"%lld\\n\", next - base); }",
"2\n") &&
RunVariableTypeScript("{ if (1 || 1 / 0) { printf(\"or short circuit\\n\"); } if (0 && 1 / 0) { printf(\"unexpected\\n\"); } printf(\"and short circuit\\n\"); }",
"or short circuit\nand short circuit\n") &&
RunVariableTypeScript("{ inferred = 0xffffffffffffffff; printf(\"%llu %lld\\n\", inferred, sizeof(inferred)); }",
"18446744073709551615 8\n") &&
RunVariableTypeScriptExpectFailure("{ unsigned float invalidValue = 1.0; }") &&
RunVariableTypeScriptExpectFailure("{ long double invalidValue = 1.0; }") &&
RunVariableTypeScriptExpectFailure("{ long long long invalidValue = 1; }") &&
RunVariableTypeScriptExpectFailure("{ local_value = 0n55; unsigned long long explicit_result = &local_value; }") &&
RunVariableTypeScriptExpectFailure("{ int value = 1; value = value / 0; }") &&
RunVariableTypeScriptExpectFailure("{ unsigned long value = 1; value = value << 0n64; }");
}

View file

@ -13,14 +13,74 @@
namespace fs = std::filesystem;
static std::mutex SemanticOutputMutex;
static std::condition_variable SemanticOutputChanged;
static std::string SemanticOutput;
static std::set<UINT32> ExpectedSemanticCases;
static std::set<std::string> ExpectedSemanticMarkers;
static VOID
CaptureSemanticOutput(CHAR * Message)
{
if (!Message)
{
return;
}
{
std::lock_guard<std::mutex> Lock(SemanticOutputMutex);
SemanticOutput.append(Message);
}
SemanticOutputChanged.notify_all();
}
static BOOLEAN
HasAllExpectedSemanticOutput(const std::string & Output)
{
if (Output.find("was failed") != std::string::npos)
{
return FALSE;
}
std::set<UINT32> SuccessfulCases;
std::regex SuccessPattern("test case ([0-9]+) was successful");
for (std::sregex_iterator Match(Output.begin(), Output.end(), SuccessPattern), End;
Match != End;
++Match)
{
SuccessfulCases.insert((UINT32)std::stoul((*Match)[1].str()));
}
if (SuccessfulCases != ExpectedSemanticCases)
{
return FALSE;
}
for (const std::string & Marker : ExpectedSemanticMarkers)
{
if (Output.find(Marker) == std::string::npos)
{
return FALSE;
}
}
return !ExpectedSemanticCases.empty() || !ExpectedSemanticMarkers.empty();
}
static BOOLEAN
SemanticRunFinishedOrFailed(const std::string & Output)
{
return Output.find("was failed") != std::string::npos || HasAllExpectedSemanticOutput(Output);
}
/**
* @brief Read directory of semantic test cases and run each of them
*
* @param ScriptSemanticPath Path to the semantic test cases
*
* @return VOID
* @return BOOLEAN TRUE if all files were read and submitted successfully
*/
VOID
BOOLEAN
ReadDirectoryAndTestSemanticTestCases(const CHAR * ScriptSemanticPath)
{
//
@ -28,62 +88,82 @@ ReadDirectoryAndTestSemanticTestCases(const CHAR * ScriptSemanticPath)
//
try
{
for (const auto & entry : fs::directory_iterator(ScriptSemanticPath))
std::vector<fs::path> TestFiles;
for (const auto & Entry : fs::directory_iterator(ScriptSemanticPath))
{
//
// Check if the entry is a file
//
if (entry.is_regular_file())
if (Entry.is_regular_file() && Entry.path().extension() == ".ds")
{
//
// Get the file path
//
std::string FilePath = entry.path().string();
TestFiles.push_back(Entry.path());
}
}
//
// Output the file name
//
// std::cout << "Test case file: " << entry.path().filename().string() << std::endl;
std::sort(TestFiles.begin(), TestFiles.end());
if (TestFiles.empty())
{
std::cerr << "No semantic .ds files were found in: " << ScriptSemanticPath << std::endl;
return FALSE;
}
//
// Open the file and read its contents
//
std::ifstream File(FilePath);
if (File.is_open())
{
std::string Content((std::istreambuf_iterator<char>(File)),
std::istreambuf_iterator<char>());
ExpectedSemanticCases.clear();
ExpectedSemanticMarkers.clear();
//
// Display the content of the file
//
std::cout << "Executing file " << entry.path().filename().string() << std::endl;
const std::regex CasePattern("test_case([0-9]+)[[:space:]]*=[[:space:]]*1");
const std::regex MarkerPattern("//[[:space:]]*semantic-test-marker:[[:space:]]*([^\\r\\n]+)");
// std::cout << content << std::endl;
for (const auto & FilePath : TestFiles)
{
std::ifstream File(FilePath, std::ios::binary);
if (!File)
{
std::cerr << "Could not open file: " << FilePath.string() << std::endl;
return FALSE;
}
//
// Run the test case command
//
hyperdbg_u_run_command((CHAR *)Content.c_str());
std::string Content((std::istreambuf_iterator<char>(File)),
std::istreambuf_iterator<char>());
if (File.bad())
{
std::cerr << "Could not read file: " << FilePath.string() << std::endl;
return FALSE;
}
std::cout << "--------------------------------------------" << std::endl;
BOOLEAN HasExpectation = FALSE;
for (std::sregex_iterator Match(Content.begin(), Content.end(), CasePattern), End;
Match != End;
++Match)
{
ExpectedSemanticCases.insert((UINT32)std::stoul((*Match)[1].str()));
HasExpectation = TRUE;
}
for (std::sregex_iterator Match(Content.begin(), Content.end(), MarkerPattern), End;
Match != End;
++Match)
{
ExpectedSemanticMarkers.insert((*Match)[1].str());
HasExpectation = TRUE;
}
if (!HasExpectation)
{
std::cerr << "Semantic file has no enabled numbered case or semantic-test-marker: "
<< FilePath.string() << std::endl;
return FALSE;
}
//
// Close the file
//
File.close();
}
else
{
std::cerr << "Could not open file: " << FilePath << std::endl;
}
std::cout << "Executing file " << FilePath.filename().string() << std::endl;
if (hyperdbg_u_run_command(Content.data()) != 0)
{
std::cerr << "Command execution failed for: " << FilePath.string() << std::endl;
return FALSE;
}
}
}
catch (const fs::filesystem_error & e)
{
std::cerr << "Filesystem error: " << e.what() << std::endl;
return FALSE;
}
return TRUE;
}
/**
@ -94,7 +174,6 @@ ReadDirectoryAndTestSemanticTestCases(const CHAR * ScriptSemanticPath)
BOOLEAN
TestSemanticScripts()
{
INT32 TestNum = 0;
CHAR dirPath[MAX_PATH] = {0};
//
@ -119,15 +198,37 @@ TestSemanticScripts()
return FALSE;
}
//
// Run test cases
//
ReadDirectoryAndTestSemanticTestCases(dirPath);
{
std::lock_guard<std::mutex> Lock(SemanticOutputMutex);
SemanticOutput.clear();
}
hyperdbg_u_set_text_message_callback((PVOID)CaptureSemanticOutput);
BOOLEAN TestResult = ReadDirectoryAndTestSemanticTestCases(dirPath);
if (TestResult)
{
std::unique_lock<std::mutex> Lock(SemanticOutputMutex);
BOOLEAN Completed = SemanticOutputChanged.wait_for(
Lock,
std::chrono::seconds(60),
[] { return SemanticRunFinishedOrFailed(SemanticOutput); });
TestResult = Completed &&
SemanticOutput.find("was failed") == std::string::npos &&
HasAllExpectedSemanticOutput(SemanticOutput);
if (!TestResult)
{
std::cerr << "Semantic output was incomplete, timed out, or contained a failure.\n"
<< SemanticOutput << std::endl;
}
}
hyperdbg_u_unset_text_message_callback();
//
// Close the connection
//
hyperdbg_u_debug_close_remote_debugger();
return TRUE;
return TestResult;
}

View file

@ -26,3 +26,9 @@ TestCodeViewRsdsParser();
BOOLEAN
TestSemanticScripts();
BOOLEAN
TestScriptEngineFloatingPoint();
BOOLEAN
TestScriptEngineVariableTypes();

View file

@ -74,7 +74,7 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
<AdditionalDependencies>$(SolutionDir)build\bin\$(Configuration)\libhyperdbg.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(SolutionDir)build\bin\$(Configuration)\libhyperdbg.lib;$(SolutionDir)build\bin\$(Configuration)\script-engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release|x64'">
@ -99,7 +99,7 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
<AdditionalDependencies>$(SolutionDir)build\bin\$(Configuration)\libhyperdbg.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(SolutionDir)build\bin\$(Configuration)\libhyperdbg.lib;$(SolutionDir)build\bin\$(Configuration)\script-engine.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@ -113,6 +113,8 @@
<ClCompile Include="code\tests\test-pe-parser.cpp" />
<ClCompile Include="code\tests\test-parser.cpp" />
<ClCompile Include="code\tests\test-semantic-scripts.cpp" />
<ClCompile Include="code\tests\test-script-floating-point.cpp" />
<ClCompile Include="code\tests\test-script-variable-types.cpp" />
<ClCompile Include="code\tools.cpp" />
<ClCompile Include="pch.cpp" />
</ItemGroup>
@ -134,4 +136,4 @@
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
<Import Project="$(VCTargetsPath)\BuildCustomizations\marmasm.targets" />
</ImportGroup>
</Project>
</Project>

View file

@ -56,6 +56,9 @@
<ClCompile Include="code\tests\test-semantic-scripts.cpp">
<Filter>code\tests</Filter>
</ClCompile>
<ClCompile Include="code\tests\test-script-floating-point.cpp">
<Filter>code\tests</Filter>
</ClCompile>
<ClCompile Include="code\hardware\hwdbg-tests.cpp">
<Filter>code\hardware</Filter>
</ClCompile>

View file

@ -29,6 +29,11 @@ using namespace std;
#include <string>
#include <conio.h>
#include <vector>
#include <algorithm>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <set>
#include <regex>
#include <sstream>
#include <iomanip>
@ -65,3 +70,4 @@ using namespace std;
// import libhyperdbg
//
#include "SDK/imports/user/HyperDbgLibImports.h"
#include "SDK/imports/user/HyperDbgScriptImports.h"

View file

@ -268,3 +268,17 @@ CommonValidateCoreNumber(UINT32 CoreNumber)
return TRUE;
}
}
/**
* @brief Get cpuid results
*
* @param Func
* @param SubFunc
* @param CpuInfo
* @return VOID
*/
VOID
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, INT * CpuInfo)
{
CpuCpuIdEx(CpuInfo, Func, SubFunc);
}

View file

@ -1164,7 +1164,7 @@ SearchAddressWrapper(PUINT64 AddressToSaveResults,
SearchMemRequest->Address = PhysicalAddressToVirtualAddressByProcessId((PVOID)StartAddress,
SearchMemRequest->ProcessId);
EndAddress = PhysicalAddressToVirtualAddressByProcessId((PVOID)EndAddress,
SearchMemRequest->ProcessId);
SearchMemRequest->ProcessId);
}
//
@ -1312,6 +1312,223 @@ DebuggerCommandFlush(PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest
return STATUS_SUCCESS;
}
/**
* @brief Handle CPUID request in vmx-root mode
*
* @param DebuggerCpuidRequest Request with CPUID function member and output
* @return NTSTATUS
*/
NTSTATUS
DebuggerCommandCpuid(PDEBUGGER_CPUID_REQUEST_RESPONSE DebuggerCpuidRequest)
{
BOOLEAN RunCpuid = TRUE;
UINT32 CpuidRegs[4] = {0};
UINT32 FunctionId = DebuggerCpuidRequest->FunctionId;
UINT32 SubFunctionId = DebuggerCpuidRequest->SubFunctionId;
UINT32 CacheIndex;
//
// Zero out memory buffer
//
RtlZeroMemory(DebuggerCpuidRequest, SIZEOF_DEBUGGER_CPUID_REQUEST_RESPONSE);
//
// receive maximum subleaves (for special ones, e.g 14, B,...), and do some other things (e.g brand string,...)
//
switch (FunctionId)
{
//
// EAX = 4h
//
case CPUID_CACHE_PARAMETERS:
for (CacheIndex = 0;; CacheIndex++)
{
CommonCpuidInstruction(FunctionId, CacheIndex, (INT32 *)CpuidRegs);
if (CPUID_EAX_CACHE_TYPE_FIELD(CpuidRegs[0]) == 0)
{
DebuggerCpuidRequest->Leaf4MaxSubLeaf = (CacheIndex > 0) ? (CacheIndex - 1) : 0;
break;
}
}
break;
//
// EAX = 0Bh
//
case CPUID_EXTENDED_TOPOLOGY:
//
// Check if supported or not
// in order to determine maximum subleaf, we have to check whether this leaf
// is supported by the current processor or not
//
CommonCpuidInstruction(FunctionId, 0, (INT32 *)CpuidRegs);
if (CPUID_EBX_NUMBER_OF_LOGICAL_PROCESSORS_AT_THIS_LEVEL_TYPE(CpuidRegs[1]) == 0)
{
//
// not supported
//
DebuggerCpuidRequest->LeafBSupported = FALSE;
RunCpuid = FALSE;
break;
}
DebuggerCpuidRequest->LeafBSupported = TRUE;
//
// iteration for determining max subleaf supported by this leaf
//
for (CacheIndex = 0;; CacheIndex++)
{
CommonCpuidInstruction(FunctionId, CacheIndex, (INT32 *)CpuidRegs);
if (CPUID_ECX_LEVEL_TYPE(CpuidRegs[2]) == 0)
{
//
// check if CacheIndex is 0, then there are no valid sub-leaves
//
DebuggerCpuidRequest->LeafBMaxSubleaf = (CacheIndex > 0) ? (CacheIndex - 1) : 0;
break;
}
}
break;
//
// EAX = 0Dh
//
case CPUID_EXTENDED_STATE_INFORMATION:
//
// Get XCR0 bits
//
CommonCpuidInstruction(FunctionId, 0, (INT32 *)CpuidRegs);
DebuggerCpuidRequest->XCR0Vector = ((UINT64)CpuidRegs[3] << 32) | CpuidRegs[0];
//
// Get IA32_XSS bits
//
CommonCpuidInstruction(FunctionId, 1, (INT32 *)CpuidRegs);
DebuggerCpuidRequest->IA32_XSS_Vector = ((UINT64)CpuidRegs[3] << 32) | CpuidRegs[2];
break;
//
// EAX = 12h
//
case CPUID_INTEL_SGX:
//
// we need to check that if SGX is supported or not
//
CommonCpuidInstruction(7, 0, (INT32 *)CpuidRegs);
DebuggerCpuidRequest->Leaf12Supported = CPUID_EBX_SGX(CpuidRegs[1]);
if (!CPUID_EBX_SGX(CpuidRegs[1]))
{
//
// SGX not supported
//
RunCpuid = FALSE;
break;
}
//
// find max subleaf
// subleaves 0 and 1 are always valid if SGX is supported, so we start iteration from 2
//
for (CacheIndex = 2;; CacheIndex++)
{
CommonCpuidInstruction(FunctionId, CacheIndex, (INT32 *)CpuidRegs);
//
// type 0 means invalid - stop enumeration
//
if (CPUID_EAX_SUB_LEAF_TYPE(CpuidRegs[0]) == 0)
{
DebuggerCpuidRequest->Leaf12MaxSubLeaf = (CacheIndex > 0) ? (CacheIndex - 1) : 0;
break;
}
//
// Safety limit - shouldn't need more than 64 EPC sections
//
if (CacheIndex > 64)
{
DebuggerCpuidRequest->Leaf12MaxSubLeaf = CacheIndex;
break;
}
}
break;
//
// Leaves with same method to receive max subleaf: 7h, 14h, 18h (respectively)
//
case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS:
case CPUID_INTEL_PROCESSOR_TRACE_INFORMATION:
case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS:
CommonCpuidInstruction(FunctionId, 0, (INT32 *)CpuidRegs);
//
// EAX = 7h
//
if (FunctionId == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS)
{
DebuggerCpuidRequest->LeafEaxMaxSubleaf = CPUID_EAX_NUMBER_OF_SUB_LEAVES(CpuidRegs[0]);
break;
}
//
// EAX = 14h or 18h -- not 7h
//
DebuggerCpuidRequest->LeafEaxMaxSubleaf = CPUID_EAX_MAX_SUB_LEAF(CpuidRegs[0]);
break;
//
// 0x80000002 - 0x80000004 : brand string
//
case CPUID_BRAND_STRING1:
case CPUID_BRAND_STRING2:
case CPUID_BRAND_STRING3:
for (UINT32 i = 0; i < 3; i++)
{
CommonCpuidInstruction(0x80000002 + i, 0, (INT32 *)CpuidRegs);
memcpy(DebuggerCpuidRequest->BrandString + (i * 16), CpuidRegs, 16);
}
DebuggerCpuidRequest->BrandString[48] = '\0';
//
// because we already EXCLUSIVELY called CPUID for these leaves, we are not going to call it again,
// as a result the RunCpuid flag is FALSE
//
RunCpuid = FALSE;
break;
}
//
// Call CPUID function
//
if (RunCpuid)
{
CommonCpuidInstruction(FunctionId, SubFunctionId, (INT32 *)CpuidRegs);
DebuggerCpuidRequest->EAX = CpuidRegs[0];
DebuggerCpuidRequest->EBX = CpuidRegs[1];
DebuggerCpuidRequest->ECX = CpuidRegs[2];
DebuggerCpuidRequest->EDX = CpuidRegs[3];
}
//
// Ensure the response contains the correct FunctionId and SubFunctionId
// (they should already be set, but this makes it explicit)
//
DebuggerCpuidRequest->FunctionId = FunctionId;
DebuggerCpuidRequest->SubFunctionId = SubFunctionId;
DebuggerCpuidRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
return STATUS_SUCCESS;
}
/**
* @brief Perform the command finished signal
*

View file

@ -87,6 +87,46 @@ SerialConnectionCheckForTheEndOfTheBuffer(PUINT32 CurrentLoopIndex, BYTE * Buffe
return FALSE;
}
/**
* @brief Discard bytes until the next end of buffer marker to re-align the
* stream to a frame boundary after a desync
*
* @return BOOLEAN TRUE if a marker was found (stream re-aligned), FALSE if too
* many bytes arrived without one (treat the link as dead)
*/
BOOLEAN
SerialConnectionResyncToNextFrame()
{
BYTE Window[4] = {NULL_ZERO, NULL_ZERO, NULL_ZERO, NULL_ZERO};
UINT32 Discarded = 0;
while (Discarded < SERIAL_RESYNC_MAX_BYTES)
{
UCHAR RecvChar = NULL_ZERO;
if (!KdHyperDbgRecvByte(&RecvChar))
{
continue;
}
Window[0] = Window[1];
Window[1] = Window[2];
Window[2] = Window[3];
Window[3] = RecvChar;
Discarded++;
if (Window[0] == SERIAL_END_OF_BUFFER_CHAR_1 &&
Window[1] == SERIAL_END_OF_BUFFER_CHAR_2 &&
Window[2] == SERIAL_END_OF_BUFFER_CHAR_3 &&
Window[3] == SERIAL_END_OF_BUFFER_CHAR_4)
{
return TRUE;
}
}
return FALSE;
}
/**
* @brief Receive packet from the debugger
*
@ -120,10 +160,33 @@ SerialConnectionRecvBuffer(CHAR * BufferToSave,
if (!(MaxSerialPacketSize > Loop))
{
//
// Invalid buffer (size of buffer exceeds the limitation)
// Overflowed without an end of buffer marker, so the stream is
// desynced (the debugger most likely dropped the link mid-frame
// without sending the close packet). Returning FALSE here sends the
// caller straight back into the same desynced stream, which
// overflows again at once and floods the log. Log once per episode
// and resync to the next frame boundary instead.
//
LogError("Err, a buffer received in debuggee which exceeds the buffer limitation");
return FALSE;
if (!g_SerialConnectionDesyncReported)
{
LogWarning("Warning, serial stream desynced (exceeded the buffer "
"limitation with no end marker); resyncing to the next frame");
g_SerialConnectionDesyncReported = TRUE;
}
if (!SerialConnectionResyncToNextFrame())
{
//
// Too many bytes without a marker, treat the link as dead
//
return FALSE;
}
//
// Re-aligned to a frame boundary, start a fresh frame
//
Loop = 0;
continue;
}
BufferToSave[Loop] = RecvChar;
@ -136,6 +199,11 @@ SerialConnectionRecvBuffer(CHAR * BufferToSave,
Loop++;
}
//
// A full frame arrived, so the stream is back in sync
//
g_SerialConnectionDesyncReported = FALSE;
//
// Set the length
//
@ -364,6 +432,11 @@ SerialConnectionPrepare(PDEBUGGER_PREPARE_DEBUGGEE DebuggeeRequest)
return STATUS_UNSUCCESSFUL;
}
//
// Not in the desync state (reset desync flag)
//
g_SerialConnectionDesyncReported = FALSE;
//
// Prepare the structures needed for connecting remote port
//

View file

@ -2260,6 +2260,7 @@ KdDispatchAndPerformCommandsFromDebugger(PROCESSOR_DEBUGGING_STATE * DbgState)
PDEBUGGEE_CHANGE_CORE_PACKET ChangeCorePacket;
PDEBUGGEE_STEP_PACKET SteppingPacket;
PDEBUGGER_FLUSH_LOGGING_BUFFERS FlushPacket;
PDEBUGGER_CPUID_REQUEST_RESPONSE CpuidPacket;
PDEBUGGER_CALLSTACK_REQUEST CallstackPacket;
PDEBUGGER_SINGLE_CALLSTACK_FRAME CallstackFrameBuffer;
PDEBUGGER_DEBUGGER_TEST_QUERY_BUFFER TestQueryPacket;
@ -2532,6 +2533,25 @@ KdDispatchAndPerformCommandsFromDebugger(PROCESSOR_DEBUGGING_STATE * DbgState)
break;
case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_CPUID_REQUEST:
CpuidPacket = (DEBUGGER_CPUID_REQUEST_RESPONSE *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET));
//
// Receieve CPUID result
//
DebuggerCommandCpuid(CpuidPacket);
//
// Send the result of CPUID back to the debugger
//
KdResponsePacketToDebugger(DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGEE_TO_DEBUGGER,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_CPUID,
(CHAR *)CpuidPacket,
sizeof(DEBUGGER_CPUID_REQUEST_RESPONSE));
break;
case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CALLSTACK:
CallstackPacket = (DEBUGGER_CALLSTACK_REQUEST *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET));

View file

@ -410,6 +410,7 @@ DrvDispatchVmmIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotCh
PDEBUGGER_GENERAL_EVENT_DETAIL DebuggerNewEventRequest;
PDEBUGGER_MODIFY_EVENTS DebuggerModifyEventRequest;
PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest;
PDEBUGGER_CPUID_REQUEST_RESPONSE DebuggerCpuidRequest;
PDEBUGGER_PREALLOC_COMMAND DebuggerReservePreallocPoolRequest;
PDEBUGGER_PREACTIVATE_COMMAND DebuggerPreactivationRequest;
PDEBUGGER_APIC_REQUEST DebuggerApicRequest;
@ -835,6 +836,34 @@ DrvDispatchVmmIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotCh
break;
case IOCTL_DEBUGGER_CPUID:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_CPUID_REQUEST_RESPONSE,
(PVOID *)&DebuggerCpuidRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform CPUID request
//
DebuggerCommandCpuid(DebuggerCpuidRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_CPUID_REQUEST_RESPONSE, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_ATTACH_DETACH_USER_MODE_PROCESS:
//

View file

@ -101,3 +101,6 @@ CommonKillProcess(UINT32 ProcessId, PROCESS_KILL_METHODS KillingMethod);
BOOLEAN
CommonValidateCoreNumber(UINT32 CoreNumber);
VOID
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, INT * CpuInfo);

View file

@ -45,6 +45,9 @@ DebuggerCommandSearchMemory(PDEBUGGER_SEARCH_MEMORY SearchMemRequest);
NTSTATUS
DebuggerCommandFlush(PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest);
NTSTATUS
DebuggerCommandCpuid(PDEBUGGER_CPUID_REQUEST_RESPONSE DebuggerCpuidRequest);
NTSTATUS
DebuggerCommandSignalExecutionState(PDEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL DebuggerFinishedExecutionRequest);

View file

@ -213,6 +213,13 @@ BOOLEAN g_IsWaitingForUserModeProcessEntryToBeCalled;
*/
BOOLEAN g_InterceptBreakpointsAndEventsForCommandsInRemoteComputer;
/**
* Set when the serial stream desyncs so the warning is logged once per episode
* (cleared on the next good frame) instead of on every overflow
*
*/
BOOLEAN g_SerialConnectionDesyncReported;
/**
* @brief Global test flag (for testing purposes)
*

View file

@ -75,6 +75,7 @@ typedef enum _DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CLOSE_AND_UNLOAD_DEBUGGEE,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CHANGE_CORE,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_FLUSH_BUFFERS,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_CPUID_REQUEST,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CALLSTACK,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_TEST_QUERY,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CHANGE_PROCESS,
@ -117,6 +118,7 @@ typedef enum _DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_RUNNING_SCRIPT,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_FORMATS,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_FLUSH,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_CPUID,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_CALLSTACK,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_TEST_QUERY,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_REGISTERING_EVENT,

View file

@ -18,7 +18,7 @@
//////////////////////////////////////////////////
#define VERSION_MAJOR 0
#define VERSION_MINOR 22
#define VERSION_MINOR 23
#define VERSION_PATCH 0
#define BETA_VERSION FALSE
@ -436,6 +436,13 @@ const UCHAR BuildSignature[] = {
#define SERIAL_END_OF_BUFFER_CHAR_3 0xEE
#define SERIAL_END_OF_BUFFER_CHAR_4 0xFF
/**
* @brief maximum number of bytes to discard while resyncing the serial stream
* to the next end of buffer marker after a framing overflow (bounded so that a
* dead link cannot spin forever)
*/
#define SERIAL_RESYNC_MAX_BYTES (MaxSerialPacketSize * 4)
/**
* @brief count of characters for tcp end of buffer
*/

View file

@ -389,6 +389,13 @@
#define IOCTL_PERFORM_SMI_OPERATION \
CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_VMM_IOCTL + 0x26, METHOD_BUFFERED, FILE_ANY_ACCESS)
/**
* @brief ioctl, to request CPUID information in vmx-root mode
*
*/
#define IOCTL_DEBUGGER_CPUID \
CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_VMM_IOCTL + 0x27, METHOD_BUFFERED, FILE_ANY_ACCESS)
//////////////////////////////////////////////////
// HyperTrace IOCTLs //
//////////////////////////////////////////////////

View file

@ -1737,3 +1737,38 @@ static_assert(sizeof(DEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET) < PacketChunkS
"err (static_assert), size of PacketChunkSize should be bigger than DEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET");
// ==============================================================================================
#define SIZEOF_DEBUGGER_CPUID_REQUEST_RESPONSE \
sizeof(DEBUGGER_CPUID_REQUEST_RESPONSE)
/**
* @brief Request and response for CPUID information (for ucpuid.cpp, not cpuid.cpp)
*
*/
typedef struct _DEBUGGER_CPUID_REQUEST_RESPONSE
{
CHAR BrandString[49];
UINT32 EAX;
UINT32 EBX;
UINT32 ECX;
UINT32 EDX;
UINT32 FunctionId;
UINT32 SubFunctionId;
UINT32 Leaf4MaxSubLeaf;
UINT32 LeafBMaxSubleaf;
UINT32 Leaf12MaxSubLeaf;
UINT32 LeafEaxMaxSubleaf;
BOOLEAN LeafBSupported;
BOOLEAN Leaf12Supported;
UINT64 XCR0Vector;
UINT64 IA32_XSS_Vector;
UINT32 KernelStatus;
} DEBUGGER_CPUID_REQUEST_RESPONSE, *PDEBUGGER_CPUID_REQUEST_RESPONSE;
// ==============================================================================================

View file

@ -63,9 +63,28 @@ typedef struct ACTION_BUFFER {
#define SYMBOL_DEREFERENCE_LOCAL_ID_TYPE 20
#define SYMBOL_DEREFERENCE_TEMP_TYPE 21
#define SYMBOL_VALUE_KIND_INTEGER 0
#define SYMBOL_VALUE_KIND_FLOAT32 1
#define SYMBOL_VALUE_KIND_FLOAT64 2
#define SCRIPT_ENGINE_ADDRESS_SPACE_LOCAL 1
#define SCRIPT_ENGINE_ADDRESS_SPACE_REMOTE 2
#define SCRIPT_SCALAR_TYPE_INVALID 0
#define SCRIPT_SCALAR_TYPE_BOOL 1
#define SCRIPT_SCALAR_TYPE_I8 2
#define SCRIPT_SCALAR_TYPE_I16 3
#define SCRIPT_SCALAR_TYPE_I32 4
#define SCRIPT_SCALAR_TYPE_I64 5
#define SCRIPT_SCALAR_TYPE_U8 6
#define SCRIPT_SCALAR_TYPE_U16 7
#define SCRIPT_SCALAR_TYPE_U32 8
#define SCRIPT_SCALAR_TYPE_U64 9
#define SCRIPT_SCALAR_TYPE_F32 10
#define SCRIPT_SCALAR_TYPE_F64 11
#define SCRIPT_SCALAR_TYPE_POINTER 12
#define SCRIPT_SCALAR_TYPE_F80 13
static const char *const SymbolTypeNames[] = {
"SYMBOL_UNDEFINED",
"SYMBOL_GLOBAL_ID_TYPE",
@ -226,6 +245,40 @@ static const char *const SymbolTypeNames[] = {
#define FUNC_MEMBER_ARROW_LVALUE 126
#define FUNC_MEMBER_DOT_READ 127
#define FUNC_MEMBER_ARROW_READ 128
#define FUNC_MOV_FLOAT 129
#define FUNC_NEG_FLOAT 130
#define FUNC_ADD_FLOAT 131
#define FUNC_SUB_FLOAT 132
#define FUNC_MUL_FLOAT 133
#define FUNC_DIV_FLOAT 134
#define FUNC_GT_FLOAT 135
#define FUNC_LT_FLOAT 136
#define FUNC_EGT_FLOAT 137
#define FUNC_ELT_FLOAT 138
#define FUNC_EQUAL_FLOAT 139
#define FUNC_NEQ_FLOAT 140
#define FUNC_CONVERT_FLOAT 141
#define FUNC_CAST_SCALAR 142
#define FUNC_ADD_TYPED 143
#define FUNC_SUB_TYPED 144
#define FUNC_MUL_TYPED 145
#define FUNC_DIV_TYPED 146
#define FUNC_MOD_TYPED 147
#define FUNC_BITWISE_AND_TYPED 148
#define FUNC_BITWISE_OR_TYPED 149
#define FUNC_BITWISE_XOR_TYPED 150
#define FUNC_SHIFT_LEFT_TYPED 151
#define FUNC_SHIFT_RIGHT_TYPED 152
#define FUNC_GT_TYPED 153
#define FUNC_LT_TYPED 154
#define FUNC_EGT_TYPED 155
#define FUNC_ELT_TYPED 156
#define FUNC_EQUAL_TYPED 157
#define FUNC_NEQ_TYPED 158
#define FUNC_NEG_TYPED 159
#define FUNC_BITWISE_NOT_TYPED 160
#define FUNC_LOGICAL_NOT_TYPED 161
#define FUNC_POINTER_DIFF 162
static const char *const FunctionNames[] = {
"FUNC_UNDEFINED",
@ -357,6 +410,40 @@ static const char *const FunctionNames[] = {
"FUNC_MEMBER_ARROW_LVALUE",
"FUNC_MEMBER_DOT_READ",
"FUNC_MEMBER_ARROW_READ",
"FUNC_MOV_FLOAT",
"FUNC_NEG_FLOAT",
"FUNC_ADD_FLOAT",
"FUNC_SUB_FLOAT",
"FUNC_MUL_FLOAT",
"FUNC_DIV_FLOAT",
"FUNC_GT_FLOAT",
"FUNC_LT_FLOAT",
"FUNC_EGT_FLOAT",
"FUNC_ELT_FLOAT",
"FUNC_EQUAL_FLOAT",
"FUNC_NEQ_FLOAT",
"FUNC_CONVERT_FLOAT",
"FUNC_CAST_SCALAR",
"FUNC_ADD_TYPED",
"FUNC_SUB_TYPED",
"FUNC_MUL_TYPED",
"FUNC_DIV_TYPED",
"FUNC_MOD_TYPED",
"FUNC_BITWISE_AND_TYPED",
"FUNC_BITWISE_OR_TYPED",
"FUNC_BITWISE_XOR_TYPED",
"FUNC_SHIFT_LEFT_TYPED",
"FUNC_SHIFT_RIGHT_TYPED",
"FUNC_GT_TYPED",
"FUNC_LT_TYPED",
"FUNC_EGT_TYPED",
"FUNC_ELT_TYPED",
"FUNC_EQUAL_TYPED",
"FUNC_NEQ_TYPED",
"FUNC_NEG_TYPED",
"FUNC_BITWISE_NOT_TYPED",
"FUNC_LOGICAL_NOT_TYPED",
"FUNC_POINTER_DIFF",
};
typedef enum REGS_ENUM {

View file

@ -131,6 +131,9 @@ hyperdbg_u_set_text_message_callback_using_shared_buffer(PVOID handler);
IMPORT_EXPORT_LIBHYPERDBG VOID
hyperdbg_u_unset_text_message_callback();
IMPORT_EXPORT_LIBHYPERDBG BOOLEAN
hyperdbg_u_test_script_engine(CHAR * expression);
IMPORT_EXPORT_LIBHYPERDBG INT
hyperdbg_u_script_read_file_and_execute_commandline(INT argc, CHAR * argv[]);
@ -326,6 +329,13 @@ hyperdbg_u_pt_operation(HYPERTRACE_PT_OPERATION_PACKETS * PtRequest);
IMPORT_EXPORT_LIBHYPERDBG BOOLEAN
hyperdbg_u_pt_mmap(HYPERTRACE_PT_MMAP_PACKETS * MmapRequest);
//
// CPUID related command
// Exported functionality of the 'ucpuid', and 'cpuid' commands
//
IMPORT_EXPORT_LIBHYPERDBG BOOLEAN
hyperdbg_u_request_cpuid(UINT32 FunctionId, UINT32 SubFunctionId);
//
// Transparent mode related command
// Exported functionality of the '!hide', and '!unhide' commands

View file

@ -93,6 +93,8 @@
* @brief Test case parameter for testing semantic script tests
*/
#define TEST_CASE_PARAMETER_FOR_SCRIPT_SEMANTIC_TEST_CASES "test-script-semantic-test-cases"
#define TEST_CASE_PARAMETER_FOR_SCRIPT_FLOATING_POINT "test-script-floating-point"
#define TEST_CASE_PARAMETER_FOR_SCRIPT_VARIABLE_TYPES "test-script-variable-types"
/**
* @brief Test cases file name

View file

@ -44,11 +44,22 @@
# define _Out_writes_bytes_(x)
# define _Inout_updates_bytes_all_(x)
// The following libc headers exist only in user space; a Linux KERNEL build
// (HYPERDBG_KERNEL_MODE) has no libc, so they are guarded out there. User-mode
// Linux is unaffected — HYPERDBG_KERNEL_MODE is never defined in that path.
# ifndef HYPERDBG_KERNEL_MODE
// wchar_t is a C++ built-in but needs this header in C
# include <wchar.h>
# include <wchar.h>
// POSIX sleep primitives (usleep) backing the Win32 Sleep() shim below
# include <unistd.h>
# include <unistd.h>
// DECIMAL_DIG and the FLT/DBL limits (ISO C99 <float.h>); MSVC exposes these
// transitively through its CRT/pch, glibc needs the explicit include
# include <float.h>
# endif // !HYPERDBG_KERNEL_MODE
// Windows string/char types
typedef char TCHAR;
@ -60,6 +71,19 @@ typedef const char * PCSTR;
typedef char * PSTR;
typedef short * PWCHAR;
// Windows generic type aliases (winnt.h): CONST is the const qualifier keyword,
// FLOAT is a plain float. Kept so shared source using the Win32 spellings
// compiles unchanged.
# define CONST const
typedef float FLOAT;
// MSVC secure-CRT truncation sentinel and status code (crtdefs.h / errno.h).
// _TRUNCATE passed as the count to strncpy_s and friends means "copy as much as
// fits and always null-terminate"; STRUNCATE is what they return when that
// truncation actually happened. Kept at their canonical MSVC values.
# define _TRUNCATE ((SIZE_T)-1)
# define STRUNCATE 80
// Windows socket type (Linux sockets are plain int)
typedef int SOCKET;
# define INVALID_SOCKET ((SOCKET)(-1))
@ -106,4 +130,24 @@ typedef void * HMODULE;
# define ERROR_ACCESS_DENIED 5
# define ERROR_GEN_FAILURE 31
// Win32 serial baud-rate constants (winbase.h CBR_*), kept at their Windows
// values so the shared serial-config / baud-rate-validation code compiles
// unchanged. Each constant equals its baud rate; actual Linux serial I/O is
// handled by the platform-serial layer (termios impl still TODO).
# define CBR_110 110
# define CBR_300 300
# define CBR_600 600
# define CBR_1200 1200
# define CBR_2400 2400
# define CBR_4800 4800
# define CBR_9600 9600
# define CBR_14400 14400
# define CBR_19200 19200
# define CBR_38400 38400
# define CBR_56000 56000
# define CBR_57600 57600
# define CBR_115200 115200
# define CBR_128000 128000
# define CBR_256000 256000
#endif // HYPERDBG_ENV_LINUX

View file

@ -1,6 +1,6 @@
/**
* @file nt-list.h
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief Cross-platform NT-style intrusive doubly-linked list helpers + CONTAINING_RECORD
* @details The shared debugger code uses the NT LIST_ENTRY API (InitializeListHead,
* InsertHeadList, RemoveEntryList, CONTAINING_RECORD, ...). On Windows these

View file

@ -29,8 +29,8 @@ PlatformCpuGetActiveProcessorCount(VOID)
#elif defined(__linux__)
# error "Not yet implemented"
return num_online_cpus();
#else
# error "Unsupported platform"
@ -52,7 +52,7 @@ PlatformCpuGetCurrentProcessorNumber(VOID)
#elif defined(__linux__)
# error "Not yet implemented"
return raw_smp_processor_id();
#else

View file

@ -33,9 +33,10 @@ PlatformDbgPrint(const CHAR * Format, ...)
va_end(ArgList);
#elif defined(__linux__)
# error "Not yet implemented"
va_list ArgList;
va_start(ArgList, Format);
vprintk(Format, ArgList);
va_end(ArgList);
#else
# error "Unsupported platform"

View file

@ -13,6 +13,7 @@
#if defined(__linux__)
# include "../../../../include/SDK/HyperDbgSdk.h"
# include <linux/cpumask.h>
#endif // defined(__linux__)
//////////////////////////////////////////////////

View file

@ -1,6 +1,6 @@
/**
* @file platform-ioctl.c
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform implementation of the local kernel-driver IOCTL transport
* @details See platform-ioctl.h. The Windows branch forwards directly to Win32
* DeviceIoControl / CreateFileA. The Linux branch is currently stubbed and is

View file

@ -1,6 +1,6 @@
/**
* @file platform-lib-calls.c
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode Cross platform APIs for platofrm dependend library calls
* @details
* @version 0.19
@ -19,7 +19,10 @@
# include <errno.h>
# include <stdint.h>
# include <string.h>
# include <strings.h>
# include <signal.h>
# include <dlfcn.h>
# include <time.h> // clock_gettime / CLOCK_MONOTONIC (PlatformQueryPerformanceCounter)
#endif // defined(__linux__)
/**
@ -163,6 +166,43 @@ PlatformSprintf(char * Buffer, SIZE_T BufferSize, const char * Format, ...)
return Result;
}
/**
* @brief Platform independent wrapper for _snprintf_s(..., _TRUNCATE, ...)
*
* Writes a formatted string into Buffer. If the output is larger than the
* buffer, it is truncated and always null-terminated.
*
* @param Buffer output buffer
* @param BufferSize size of the output buffer
* @param Format format string
* @return INT number of characters written, or -1 if truncation or an error occurred.
*/
INT
PlatformSnprintf(char * Buffer, SIZE_T BufferSize, const char * Format, ...)
{
va_list Args;
INT Result;
va_start(Args, Format);
#if defined(_WIN32)
Result = _vsnprintf_s(Buffer, BufferSize, _TRUNCATE, Format, Args);
#elif defined(__linux__)
Result = vsnprintf(Buffer, BufferSize, Format, Args);
/* Match Windows _TRUNCATE behavior: return -1 on truncation. */
if (Result >= 0 && (SIZE_T)Result >= BufferSize)
{
Result = -1;
}
#else
# error "Unsupported platform"
#endif
va_end(Args);
return Result;
}
/**
* @brief Platform independent wrapper for strnlen_s / strnlen
*
@ -231,6 +271,99 @@ PlatformStrCpy(char * Dest, SIZE_T DestSize, const char * Src)
#endif
}
/**
* @brief Platform independent wrapper for strncpy_s
*
* @details Copies the first D characters of Src into the DestSize-byte Dest
* buffer and appends a null terminator, where D is the lesser of Count and the
* length of Src. If those characters do not fit while still leaving room for the
* terminator, Dest is set to an empty string and a non-zero error is returned.
* Passing _TRUNCATE as Count instead copies as much of Src as fits, returning
* STRUNCATE when anything had to be dropped. On Linux there is no standard
* strncpy_s, so this reproduces those same rules.
*
* @param Dest destination buffer
* @param DestSize size of the destination buffer in bytes
* @param Src source string
* @param Count maximum characters to copy, or _TRUNCATE
* @return INT 0 on success, STRUNCATE if truncated, non-zero on failure
*/
INT
PlatformStrNCpy(char * Dest, SIZE_T DestSize, const char * Src, SIZE_T Count)
{
#if defined(_WIN32)
return strncpy_s(Dest, DestSize, Src, Count);
#elif defined(__linux__)
// NOT YET TESTED!! So needs some testing to see if it actually behaves the same as strncpy_s on windows
SIZE_T Length;
if (Dest == NULL || DestSize == 0 || Src == NULL)
{
if (Dest != NULL && DestSize != 0)
{
Dest[0] = '\0';
}
return -1;
}
//
// Never read past Count characters of Src; it need not be null-terminated
// within that span
//
Length = PlatformStrnlen(Src, Count == _TRUNCATE ? DestSize : Count);
if (Count == _TRUNCATE)
{
//
// Copy as much as fits and report whether anything was dropped
//
if (Length >= DestSize)
{
memcpy(Dest, Src, DestSize - 1);
Dest[DestSize - 1] = '\0';
return STRUNCATE;
}
}
else if (Length >= DestSize)
{
//
// Source does not fit (need room for the null terminator too)
//
Dest[0] = '\0';
return -1;
}
memcpy(Dest, Src, Length);
Dest[Length] = '\0';
return 0;
#else
# error "Unsupported platform"
#endif
}
/**
* @brief Platform independent wrapper for _stricmp
*
* @details Compares two strings ignoring case. Returns 0 when equal; a value
* less/greater than zero otherwise. Linux uses strcasecmp, which has the same
* semantics as the Win32 CRT's _stricmp.
*
* @param Str1 first string
* @param Str2 second string
* @return INT 0 if equal (case-insensitively), non-zero otherwise
*/
INT
PlatformStrCaseCmp(const char * Str1, const char * Str2)
{
#if defined(_WIN32)
return _stricmp(Str1, Str2);
#elif defined(__linux__)
return strcasecmp(Str1, Str2);
#else
# error "Unsupported platform"
#endif
}
/**
* @brief Platform independent wrapper for Sleep / usleep
*
@ -299,6 +432,27 @@ PlatformGetCurrentProcessorNumber(VOID)
#endif
}
/**
* @brief Platform independent count of online logical processors
*
* @return SIZE_T number of logical processors online, or 0 if unknown
*/
SIZE_T
PlatformGetActiveProcessorCount(VOID)
{
#if defined(_WIN32)
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
return (SIZE_T)SysInfo.dwNumberOfProcessors;
#elif defined(__linux__)
// Not yet tested!!
long Count = sysconf(_SC_NPROCESSORS_ONLN);
return Count > 0 ? (SIZE_T)Count : 0;
#else
# error "Unsupported platform"
#endif
}
/**
* @brief Platform independent wrapper for GetCurrentProcessId / getpid
*
@ -492,6 +646,47 @@ PlatformCreateThread(PLATFORM_THREAD_ROUTINE Routine, PVOID Param)
#endif
}
/**
* @brief Platform independent wrapper for TerminateThread
*
* @details There is no POSIX equivalent by design: no call forcibly kills a
* thread without unwinding, since doing so never releases the
* target's locks. pthread_cancel is the nearest primitive but has
* different semantics (deferred by default, and glibc implements it
* as a forced unwind that runs destructors and cleanup handlers).
*
* TODO (linux): the only caller is disconnect.cpp, whose listening
* thread blocks in recv() inside a
* `while (g_IsConnectedToRemoteDebuggee)` loop and breaks on any
* receive error. The correct teardown there is to clear the flag,
* shutdown(fd, SHUT_RDWR) to kick the thread out of recv, then
* pthread_join it letting it exit through its own error path, with
* no cancellation primitive involved. That needs a call-site reorder
* (teardown before thread-kill, and SD_SEND -> SHUT_RDWR to wake a
* blocked reader), which the port's no-logic-changes rule defers.
*
* Returning TRUE is consistent with PlatformCreateThread, which
* returns NULL on Linux the thread is never started there, so
* there is nothing to terminate yet.
*
* @param Thread handle to the thread to terminate
* @param ExitCode exit code for the terminated thread
* @return BOOLEAN TRUE on success
*/
BOOLEAN
PlatformTerminateThread(HANDLE Thread, DWORD ExitCode)
{
#if defined(_WIN32)
return (BOOLEAN)TerminateThread(Thread, ExitCode);
#elif defined(__linux__)
(void)Thread;
(void)ExitCode;
return TRUE;
#else
# error "Unsupported platform"
#endif
}
/**
* @brief Platform independent wrapper for GetLastError
*/
@ -557,6 +752,46 @@ PlatformOpenFileForWriting(const WCHAR * Path)
#endif
}
/**
* @brief Platform independent wrapper to open a file for writing with
* OPEN_ALWAYS semantics (open existing without truncating, else create),
* taking a narrow (char*) path
*
* @details Unlike PlatformOpenFileForWriting (wide path, CREATE_ALWAYS/truncate)
* this keeps any existing file content. The Linux handle is a FILE* so
* it works with PlatformWriteFile / PlatformCloseFile.
*
* @param Path narrow path of the file to open or create
* @return HANDLE to the opened file, or INVALID_HANDLE_VALUE on failure
*/
HANDLE
PlatformOpenFileForWritingNarrow(const CHAR * Path)
{
#if defined(_WIN32)
return CreateFileA(Path, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
#elif defined(__linux__)
//
// NOT YET TESTED!!
// "r+b" opens an existing file at offset 0 without truncating (matching
// OPEN_ALWAYS on an existing file); if it does not exist, create it with
// "w+b". Return the FILE* as the HANDLE (PlatformWriteFile/PlatformCloseFile
// treat the Linux handle as a FILE*).
//
FILE * File = fopen(Path, "r+b");
if (File == NULL)
{
File = fopen(Path, "w+b");
}
if (File == NULL)
{
return INVALID_HANDLE_VALUE;
}
return (HANDLE)File;
#else
# error "Unsupported platform"
#endif
}
/**
* @brief Platform independent wrapper to write a buffer to an open file
*
@ -904,3 +1139,65 @@ PlatformGetExitCodeProcess(HANDLE Process, LPDWORD ExitCode)
# error "Unsupported platform"
#endif
}
/**
* @brief Platform independent wrapper for LoadLibrary
*
* @param ModulePath narrow path of the shared module to load
* @return HMODULE handle to the loaded module, or NULL on failure
*/
HMODULE
PlatformLoadLibrary(const CHAR * ModulePath)
{
#if defined(_WIN32)
return LoadLibraryA(ModulePath);
#elif defined(__linux__)
// NOT YET TESTED!!
return (HMODULE)dlopen(ModulePath, RTLD_NOW | RTLD_LOCAL);
#else
# error "Unsupported platform"
#endif
}
/**
* @brief Platform independent wrapper for GetProcAddress
*
* @param Module module handle returned by PlatformLoadLibrary
* @param ProcName name of the exported symbol to resolve
* @return PVOID address of the symbol, or NULL if not found
*/
PVOID
PlatformGetProcAddress(HMODULE Module, const CHAR * ProcName)
{
#if defined(_WIN32)
return (PVOID)GetProcAddress(Module, ProcName);
#elif defined(__linux__)
// NOT YET TESTED!!
return dlsym((void *)Module, ProcName);
#else
# error "Unsupported platform"
#endif
}
/**
* @brief Platform independent wrapper for FreeLibrary
*
* @param Module module handle returned by PlatformLoadLibrary
* @return BOOL non-zero on success, zero on failure
*/
BOOL
PlatformFreeLibrary(HMODULE Module)
{
#if defined(_WIN32)
return FreeLibrary(Module);
#elif defined(__linux__)
//
// NOT YET TESTED!!
// dlclose returns 0 on success (opposite of FreeLibrary), so invert it to
// preserve the "non-zero == success" contract.
//
return (BOOL)(dlclose((void *)Module) == 0);
#else
# error "Unsupported platform"
#endif
}

View file

@ -1,6 +1,6 @@
/**
* @file platform-serial.c
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform implementation of the kernel-debugger serial transport
* @details See platform-serial.h. The Windows branch wraps the Win32 serial primitives
* (CreateFile / Comm* / overlapped ReadFile/WriteFile) and owns the per-direction
@ -23,185 +23,8 @@
#if defined(_WIN32)
//
// Per-direction overlapped I/O state, owned by the transport layer.
// Not implemented here
//
static OVERLAPPED g_PlatformOverlappedReadDebugger = {0};
static OVERLAPPED g_PlatformOverlappedReadDebuggee = {0};
static OVERLAPPED g_PlatformOverlappedWriteDebugger = {0};
HANDLE
PlatformSerialOpen(const char * PortName, PLATFORM_SERIAL_IO_ROLE Role)
{
HANDLE Comm;
char PortNo[24] = {0};
//
// Append name to make a Windows-understandable format
//
sprintf_s(PortNo, sizeof(PortNo), "\\\\.\\%s", PortName);
if (Role == PLATFORM_SERIAL_IO_DEBUGGEE)
{
//
// Debuggee uses non-overlapped (blocking) I/O
//
Comm = CreateFile(PortNo,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
g_PlatformOverlappedReadDebuggee.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
else
{
//
// Debugger uses overlapped (async) I/O
//
Comm = CreateFile(PortNo,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
g_PlatformOverlappedReadDebugger.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
g_PlatformOverlappedWriteDebugger.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
if (Comm == INVALID_HANDLE_VALUE)
{
return NULL;
}
//
// Purge the serial port
//
PurgeComm(Comm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
return Comm;
}
BOOLEAN
PlatformSerialConfigure(HANDLE Handle, DWORD BaudRate)
{
DCB SerialParams = {0};
SerialParams.DCBlength = sizeof(SerialParams);
if (GetCommState(Handle, &SerialParams) == FALSE)
{
return FALSE;
}
SerialParams.BaudRate = BaudRate;
SerialParams.ByteSize = 8;
SerialParams.StopBits = ONESTOPBIT;
SerialParams.Parity = NOPARITY;
if (SetCommState(Handle, &SerialParams) == FALSE)
{
return FALSE;
}
return TRUE;
}
BOOLEAN
PlatformSerialReadByte(HANDLE Handle,
CHAR * OutByte,
DWORD * BytesRead,
PLATFORM_SERIAL_IO_ROLE Role)
{
OVERLAPPED * Ovl = (Role == PLATFORM_SERIAL_IO_DEBUGGEE)
? &g_PlatformOverlappedReadDebuggee
: &g_PlatformOverlappedReadDebugger;
if (Role == PLATFORM_SERIAL_IO_DEBUGGEE)
{
//
// Apply a read timeout for the debuggee side
//
COMMTIMEOUTS Timeouts;
GetCommTimeouts(Handle, &Timeouts);
Timeouts.ReadIntervalTimeout = MAXDWORD;
Timeouts.ReadTotalTimeoutConstant = 5000;
Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.WriteTotalTimeoutConstant = 0;
Timeouts.WriteTotalTimeoutMultiplier = 0;
SetCommTimeouts(Handle, &Timeouts);
}
if (!ReadFile(Handle, OutByte, sizeof(CHAR), NULL, Ovl))
{
if (GetLastError() != ERROR_IO_PENDING)
{
return FALSE;
}
}
WaitForSingleObject(Ovl->hEvent, INFINITE);
GetOverlappedResult(Handle, Ovl, BytesRead, FALSE);
ResetEvent(Ovl->hEvent);
return TRUE;
}
BOOLEAN
PlatformSerialWrite(HANDLE Handle, const void * Buffer, UINT32 Length, BOOLEAN Synchronous)
{
if (Synchronous)
{
DWORD BytesWritten = 0;
if (WriteFile(Handle, Buffer, Length, &BytesWritten, NULL) == FALSE)
{
return FALSE;
}
return (BytesWritten == Length);
}
else
{
if (WriteFile(Handle, Buffer, Length, NULL, &g_PlatformOverlappedWriteDebugger))
{
return TRUE;
}
if (GetLastError() != ERROR_IO_PENDING)
{
return FALSE;
}
if (WaitForSingleObject(g_PlatformOverlappedWriteDebugger.hEvent, INFINITE) != WAIT_OBJECT_0)
{
return FALSE;
}
ResetEvent(g_PlatformOverlappedWriteDebugger.hEvent);
return TRUE;
}
}
BOOLEAN
PlatformSerialClose(HANDLE Handle)
{
if (g_PlatformOverlappedReadDebugger.hEvent)
CloseHandle(g_PlatformOverlappedReadDebugger.hEvent);
if (g_PlatformOverlappedReadDebuggee.hEvent)
CloseHandle(g_PlatformOverlappedReadDebuggee.hEvent);
if (g_PlatformOverlappedWriteDebugger.hEvent)
CloseHandle(g_PlatformOverlappedWriteDebugger.hEvent);
g_PlatformOverlappedReadDebugger.hEvent = NULL;
g_PlatformOverlappedReadDebuggee.hEvent = NULL;
g_PlatformOverlappedWriteDebugger.hEvent = NULL;
if (Handle)
return (BOOLEAN)CloseHandle(Handle);
return TRUE;
}
#elif defined(__linux__)
@ -258,13 +81,6 @@ PlatformSerialWrite(HANDLE Handle, const void * Buffer, UINT32 Length, BOOLEAN S
return FALSE;
}
BOOLEAN
PlatformSerialClose(HANDLE Handle)
{
(void)Handle;
return TRUE;
}
#else
# error "Unsupported platform"
#endif

View file

@ -1,6 +1,6 @@
/**
* @file platform-signal.c
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform implementation of the console-control handler
* @details See platform-signal.h. The Windows branch forwards to SetConsoleCtrlHandler.
* The Linux branch blocks the handled signals and dispatches them from a

View file

@ -0,0 +1,83 @@
/**
* @file platform-socket.c
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform implementation of the TCP remote-debugging transport
* @details See platform-socket.h. The few Winsock/POSIX primitives that diverge
* (close, shutdown flag, last-error) are mapped onto a common spelling
* by the macros below so each wrapper body is written once; only the
* startup/cleanup lifecycle, whose structure genuinely differs, keeps a
* small in-body guard. The portable socket calls themselves stay at the
* tcpclient/tcpserver call sites unchanged.
*
* @version 0.21
* @date 2026-07-22
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
#if defined(__linux__)
# include "../header/platform-socket.h"
# include <errno.h>
#endif // defined(__linux__)
//
// Map the Winsock/POSIX primitives that diverge onto a common spelling.
//
#if defined(_WIN32)
# define PLATFORM_CLOSE_SOCKET(Socket) closesocket(Socket)
# define PLATFORM_SHUTDOWN_SEND_FLAG SD_SEND
# define PLATFORM_LAST_SOCKET_ERROR WSAGetLastError()
#elif defined(__linux__)
# define PLATFORM_CLOSE_SOCKET(Socket) close(Socket)
# define PLATFORM_SHUTDOWN_SEND_FLAG SHUT_WR
# define PLATFORM_LAST_SOCKET_ERROR errno
#endif
INT
PlatformSocketInitialize(VOID)
{
#if defined(_WIN32)
WSADATA WsaData;
//
// Request Winsock 2.2; the WSADATA is not needed by the caller.
//
return WSAStartup(MAKEWORD(2, 2), &WsaData);
#else
//
// No global socket-library initialization is needed on Linux.
//
return 0;
#endif
}
VOID
PlatformSocketCleanup(VOID)
{
#if defined(_WIN32)
WSACleanup();
#endif
//
// Nothing to tear down on Linux.
//
}
INT
PlatformCloseSocket(SOCKET Socket)
{
return PLATFORM_CLOSE_SOCKET(Socket);
}
INT
PlatformShutdownSocketSend(SOCKET Socket)
{
return shutdown(Socket, PLATFORM_SHUTDOWN_SEND_FLAG);
}
INT
PlatformGetSocketError(VOID)
{
return PLATFORM_LAST_SOCKET_ERROR;
}

View file

@ -1,6 +1,6 @@
/**
* @file platform-ioctl.h
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform interface for the local kernel-driver IOCTL transport
* @details Distinct from the serial transport (platform-serial), which talks to a remote
* debuggee. This interface is the LOCAL control channel: the userspace library

View file

@ -1,6 +1,6 @@
/**
* @file platform-lib-calls.h
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode Cross platform APIs for platofrm dependend library calls
* @details
* @version 0.19
@ -48,6 +48,12 @@ PlatformCopyMemory(PVOID Destination, const VOID * Source, SIZE_T Size);
INT
PlatformSprintf(char * Buffer, SIZE_T BufferSize, const char * Format, ...);
//
// SNPRINTF
//
INT
PlatformSnprintf(char * Buffer, SIZE_T BufferSize, const char * Format, ...);
//
// BOUNDED STRING LENGTH
//
@ -64,6 +70,27 @@ PlatformStrnlen(const char * Str, SIZE_T MaxLength);
INT
PlatformStrCpy(char * Dest, SIZE_T DestSize, const char * Src);
//
// BOUNDED COUNTED STRING COPY
//
// Mirrors strncpy_s: copies at most Count characters of Src into Dest (of
// DestSize bytes) and always null-terminates. Passing _TRUNCATE as Count means
// "copy as much as fits", returning STRUNCATE if it had to truncate. Otherwise
// returns 0 on success, non-zero if the arguments are invalid or Count does not
// fit (in which case Dest is left as an empty string).
//
INT
PlatformStrNCpy(char * Dest, SIZE_T DestSize, const char * Src, SIZE_T Count);
//
// CASE-INSENSITIVE STRING COMPARE
//
// Mirrors _stricmp: returns 0 when the strings are equal ignoring case, and a
// negative/positive value otherwise. Linux uses strcasecmp (same semantics).
//
INT
PlatformStrCaseCmp(const char * Str1, const char * Str2);
//
// SLEEP (milliseconds)
//
@ -74,7 +101,7 @@ PlatformSleep(DWORD Milliseconds);
// DEBUG BREAK (raise a breakpoint trap in the calling process)
//
VOID
PlatformDebugBreak(VOID);
PlatformDebugBreak(VOID);
//
// HIGH-RESOLUTION PERFORMANCE COUNTER
@ -115,6 +142,9 @@ typedef DWORD(WINAPI * PLATFORM_THREAD_ROUTINE)(PVOID Param);
HANDLE
PlatformCreateThread(PLATFORM_THREAD_ROUTINE Routine, PVOID Param);
BOOLEAN
PlatformTerminateThread(HANDLE Thread, DWORD ExitCode);
//
// LAST OS ERROR
//
@ -145,6 +175,16 @@ PlatformWriteConsole(const VOID * Buffer, DWORD NumberOfBytes);
HANDLE
PlatformOpenFileForWriting(const WCHAR * Path);
//
// Narrow (char*) variant with OPEN_ALWAYS semantics (open existing, else
// create; no truncate), as opposed to the wide PlatformOpenFileForWriting above
// which truncates (CREATE_ALWAYS). Used by the event-forwarding file sink, whose
// path is already a narrow std::string, so it sidesteps the wide-char issue and
// works on Linux.
//
HANDLE
PlatformOpenFileForWritingNarrow(const CHAR * Path);
BOOLEAN
PlatformWriteFile(HANDLE FileHandle, const VOID * Buffer, DWORD NumberOfBytes);
@ -176,6 +216,18 @@ PlatformGetCurrentThreadId(VOID);
UINT32
PlatformGetCurrentProcessorNumber(VOID);
//
// Number of logical processors currently online. Windows uses the classic
// GetSystemInfo count; Linux uses sysconf(_SC_NPROCESSORS_ONLN). Returns 0 if
// the count cannot be determined.
//
// NOTE: rdmsr.cpp keeps its own NUMA-aware GetLogicalProcessorInformationEx
// chain on Windows and only falls back to this wrapper on Linux, so the
// Windows core count there is unchanged.
//
SIZE_T
PlatformGetActiveProcessorCount(VOID);
UINT32
PlatformGetCurrentProcessId(VOID);
@ -204,3 +256,20 @@ PlatformResumeThread(HANDLE Thread);
BOOL
PlatformGetExitCodeProcess(HANDLE Process, LPDWORD ExitCode);
//
// DYNAMIC LIBRARY LOADING
//
// Thin wrappers over LoadLibrary/GetProcAddress/FreeLibrary, used by the
// event-forwarding "module" sink (loads a plugin exporting
// hyperdbg_event_forwarding). Windows = the Win32 calls; Linux = dlopen/dlsym/
// dlclose (exact 1:1 semantic map).
//
HMODULE
PlatformLoadLibrary(const CHAR * ModulePath);
PVOID
PlatformGetProcAddress(HMODULE Module, const CHAR * ProcName);
BOOL
PlatformFreeLibrary(HMODULE Module);

View file

@ -1,6 +1,6 @@
/**
* @file platform-serial.h
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform interface for the kernel-debugger serial transport
* @details The kernel-debugging *protocol* in kd.cpp is platform independent; only
* the byte transport underneath it (serial COM port / named pipe) is OS

View file

@ -1,6 +1,6 @@
/**
* @file platform-signal.h
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform interface for the console-control (CTRL+C / CTRL+BREAK) handler
* @details HyperDbg installs a single handler (BreakController) that pauses the
* debuggee when the user hits CTRL+C / CTRL+BREAK. The handler body is

View file

@ -0,0 +1,78 @@
/**
* @file platform-socket.h
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief User mode cross-platform interface for the TCP remote-debugging transport
* @details The remote-debugging command/result exchange in tcpclient.cpp /
* tcpserver.cpp is written against the BSD-socket API, which Winsock and
* POSIX share almost verbatim (socket / connect / bind / listen / accept /
* send / recv / shutdown / getaddrinfo). Only a handful of things diverge:
* Winsock's startup/cleanup lifecycle, closesocket vs close(2), the
* SD_SEND vs SHUT_WR shutdown flag, WSAGetLastError vs errno, and the
* address-length out-parameter type of accept() (int vs socklen_t). Those
* are isolated behind the Platform* wrappers / typedef below so the socket
* call sites stay shared. On Linux this header also pulls in the POSIX
* socket headers that back the portable calls; on Windows they come from
* <winsock2.h>/<ws2tcpip.h> (included by pch.h).
*
* @version 0.21
* @date 2026-07-22
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#pragma once
#if defined(__linux__)
# include "../../../../include/SDK/HyperDbgSdk.h"
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <unistd.h>
#endif // defined(__linux__)
//
// Length type for the address-size out-parameter of accept() (and friends).
// Winsock uses int; POSIX uses socklen_t. Kept as a platform typedef so the
// call sites declare the right type without an inline #ifdef.
//
#if defined(_WIN32)
typedef int PLATFORM_SOCKLEN;
#elif defined(__linux__)
typedef socklen_t PLATFORM_SOCKLEN;
#endif
//
// INITIALIZE the socket subsystem before any socket call. Mirrors WSAStartup:
// returns 0 on success and non-zero on failure. The Winsock version request is
// kept internal. No-op on Linux (always returns 0).
//
INT
PlatformSocketInitialize(VOID);
//
// CLEAN UP the socket subsystem (Winsock WSACleanup; no-op on Linux).
//
VOID
PlatformSocketCleanup(VOID);
//
// CLOSE a socket (Winsock closesocket; POSIX close(2)).
//
INT
PlatformCloseSocket(SOCKET Socket);
//
// SHUT DOWN the sending side of a socket (Winsock shutdown(.., SD_SEND);
// POSIX shutdown(.., SHUT_WR)). Returns 0 on success, SOCKET_ERROR on failure.
//
INT
PlatformShutdownSocketSend(SOCKET Socket);
//
// LAST socket error for the calling thread (Winsock WSAGetLastError; POSIX
// errno). See the last-error caveat in platform-lib-calls.h: the numeric code
// spaces still differ; callers that only log or check non-zero are fine.
//
INT
PlatformGetSocketError(VOID);

View file

@ -12,10 +12,15 @@ set(SourceFiles
"header/globals/globals.h"
"header/debugger/commands/help.h"
"header/hwdbg/hwdbg-interpreter.h"
"header/hwdbg/hwdbg-scripts.h"
"header/debugger/misc/inipp.h"
"header/debugger/driver-loader/install.h"
"header/debugger/kernel-level/kd.h"
"header/app/libhyperdbg.h"
"header/app/messaging.h"
"header/app/packets.h"
"header/debugger/core/steppings.h"
"header/debugger/misc/pci-id.h"
"header/common/list.h"
"header/debugger/communication/namedpipe.h"
"header/objects/objects.h"
@ -32,6 +37,7 @@ set(SourceFiles
"../include/platform/user/code/platform-serial.c"
"../include/platform/user/code/platform-ioctl.c"
"../include/platform/user/code/platform-signal.c"
"../include/platform/user/code/platform-socket.c"
"../include/platform/user/code/windows-only/windows-privilege.c"
"../script-eval/code/Functions.c"
"../script-eval/code/Keywords.c"
@ -40,17 +46,30 @@ set(SourceFiles
"../script-eval/code/ScriptEngineEval.c"
"code/common/spinlock.cpp"
"code/debugger/commands/debugging-commands/a.cpp"
"code/debugger/commands/debugging-commands/continue.cpp"
"code/debugger/commands/debugging-commands/gg.cpp"
"code/debugger/commands/debugging-commands/core.cpp"
"code/debugger/commands/debugging-commands/dt-struct.cpp"
"code/debugger/commands/debugging-commands/gu.cpp"
"code/debugger/commands/debugging-commands/k.cpp"
"code/debugger/commands/debugging-commands/preactivate.cpp"
"code/debugger/commands/debugging-commands/prealloc.cpp"
"code/debugger/commands/extension-commands/apic.cpp"
"code/debugger/commands/extension-commands/crwrite.cpp"
"code/debugger/commands/extension-commands/idt.cpp"
"code/debugger/commands/extension-commands/ioapic.cpp"
"code/debugger/commands/extension-commands/lbr.cpp"
"code/debugger/commands/extension-commands/lbrdump.cpp"
"code/debugger/commands/extension-commands/pcicam.cpp"
"code/debugger/commands/extension-commands/pcitree.cpp"
"code/debugger/commands/extension-commands/pt.cpp"
"code/debugger/commands/extension-commands/smi.cpp"
"code/debugger/commands/extension-commands/xsetbv.cpp"
"code/debugger/commands/extension-commands/rev.cpp"
"code/debugger/commands/extension-commands/trace.cpp"
"code/debugger/commands/extension-commands/track.cpp"
"code/debugger/commands/extension-commands/mode.cpp"
"code/debugger/commands/hwdbg-commands/hw.cpp"
"code/debugger/commands/hwdbg-commands/hw_clk.cpp"
"code/debugger/commands/meta-commands/dump.cpp"
"code/debugger/commands/meta-commands/kill.cpp"
@ -77,11 +96,16 @@ set(SourceFiles
"code/debugger/user-level/user-listening.cpp"
"code/export/export.cpp"
"code/hwdbg/hwdbg-interpreter.cpp"
"code/hwdbg/hwdbg-scripts.cpp"
"code/objects/objects.cpp"
"code/rev/rev-ctrl.cpp"
"pch.cpp"
"code/app/dllmain.cpp"
"code/app/libhyperdbg.cpp"
"code/app/messaging.cpp"
"code/app/packets.cpp"
"code/debugger/core/steppings.cpp"
"code/debugger/misc/pci-id.cpp"
"code/common/common.cpp"
"code/debugger/commands/debugging-commands/bc.cpp"
"code/debugger/commands/debugging-commands/bd.cpp"
@ -114,6 +138,7 @@ set(SourceFiles
"code/debugger/commands/debugging-commands/wrmsr.cpp"
"code/debugger/commands/debugging-commands/x.cpp"
"code/debugger/commands/extension-commands/cpuid.cpp"
"ucpuid.cpp"
"code/debugger/commands/extension-commands/dr.cpp"
"code/debugger/commands/extension-commands/epthook.cpp"
"code/debugger/commands/extension-commands/epthook2.cpp"
@ -159,7 +184,7 @@ set(SourceFiles
"code/debugger/tests/tests.cpp"
"code/debugger/transparency/gaussian-rng.cpp"
"code/debugger/transparency/transparency.cpp"
"code/assembly/asm-vmx-checks.asm"
"code/assembly/asm-vmx-checks-masm-windows.asm"
)
include_directories(
"../dependencies/phnt"
@ -177,6 +202,7 @@ set_source_files_properties(
"../include/platform/user/code/platform-serial.c"
"../include/platform/user/code/platform-ioctl.c"
"../include/platform/user/code/platform-signal.c"
"../include/platform/user/code/platform-socket.c"
"../include/platform/user/code/windows-only/windows-privilege.c"
"../script-eval/code/Functions.c"
"../script-eval/code/Keywords.c"
@ -193,6 +219,36 @@ if(UNIX)
list(APPEND SourceFiles "code/debugger/user-level/pe-parser-linux.cpp")
list(REMOVE_ITEM SourceFiles "code/debugger/driver-loader/install.cpp")
list(APPEND SourceFiles "code/debugger/driver-loader/install-linux.cpp")
list(REMOVE_ITEM SourceFiles "code/debugger/communication/namedpipe.cpp")
list(APPEND SourceFiles "code/debugger/communication/namedpipe-linux.cpp")
#
# pt.cpp (Intel PT command) is an un-ported Windows process-control TU
# (OpenProcess/CreateToolhelp32Snapshot/CreateThread/WaitForMultipleObjects).
# Keep it out of the Linux build until the process-control port lands and
# swap in the stub that provides its 4 externally visible functions.
#
list(REMOVE_ITEM SourceFiles "code/debugger/commands/extension-commands/pt.cpp")
list(APPEND SourceFiles "code/debugger/commands/extension-commands/pt-linux.cpp")
#
# The MASM (.asm) implementation only builds with the Microsoft assembler,
# so swap it for the GAS (AT&T syntax) port and enable the ASM language so
# CMake assembles the .s file with the system assembler.
#
list(REMOVE_ITEM SourceFiles "code/assembly/asm-vmx-checks-masm-windows.asm")
list(APPEND SourceFiles "code/assembly/asm-vmx-checks-gas-unix.s")
enable_language(ASM)
endif()
add_library(libhyperdbg SHARED ${SourceFiles})
if(UNIX)
#
# Enable the Intel TSX/RTM intrinsics (_xbegin/_xend/_XBEGIN_STARTED) used by
# CheckAddressValidityUsingTsx() in common.cpp. GCC gates these behind -mrtm.
# Harmless when unused: no RTM instructions are emitted unless the intrinsics
# are actually called.
#
target_compile_options(libhyperdbg PRIVATE -mrtm)
endif()

View file

@ -54,7 +54,7 @@ SetTextMessageCallbackUsingSharedBuffer(PVOID Handler)
return NULL;
}
RtlZeroMemory(g_MessageHandlerSharedBuffer, COMMUNICATION_BUFFER_SIZE + TCP_END_OF_BUFFER_CHARS_COUNT);
PlatformZeroMemory(g_MessageHandlerSharedBuffer, COMMUNICATION_BUFFER_SIZE + TCP_END_OF_BUFFER_CHARS_COUNT);
return g_MessageHandlerSharedBuffer;
}

View file

@ -46,18 +46,11 @@ ReadIrpBasedBuffer()
// a pending IOCTL while the main debugger handle continues sending other
// synchronous IOCTLs.
//
Handle = CreateFileA(
"\\\\.\\HyperDbgDebuggerDevice",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, /// lpSecurityAttirbutes
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL); /// lpTemplateFile
Handle = PlatformOpenDevice("\\\\.\\HyperDbgDebuggerDevice");
if (Handle == INVALID_HANDLE_VALUE)
{
ErrorNum = GetLastError();
ErrorNum = PlatformGetLastError();
if (ErrorNum == ERROR_ACCESS_DENIED)
{
@ -92,9 +85,9 @@ ReadIrpBasedBuffer()
//
// Clear the buffer
//
ZeroMemory(OutputBuffer, UsermodeBufferSize);
PlatformZeroMemory(OutputBuffer, UsermodeBufferSize);
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
Handle, // Handle to device
IOCTL_REGISTER_EVENT, // IO Control Code (IOCTL)
&RegisterEvent, // Input Buffer to driver.
@ -253,7 +246,7 @@ ReadIrpBasedBuffer()
//
// Indicate that driver (Hypervisor) is loaded successfully
//
SetEvent(g_IsDriverLoadedSuccessfully);
PlatformSetEvent(g_IsDriverLoadedSuccessfully);
break;
@ -321,9 +314,9 @@ ReadIrpBasedBuffer()
//
// close handle
//
if (!CloseHandle(Handle))
if (!PlatformCloseHandle(Handle))
{
ShowMessages("err, closing handle 0x%x\n", GetLastError());
ShowMessages("err, closing handle 0x%x\n", PlatformGetLastError());
}
}

View file

@ -0,0 +1,44 @@
/* ------------------------------------------------------------------------
* GAS (AT&T syntax) port of asm-vmx-checks-masm-windows.asm
*
* AsmVmxSupportDetection: returns 1 in rax if the CPU reports VMX support
* (CPUID.1:ECX[5]), 0 otherwise.
* ------------------------------------------------------------------------ */
.text
.globl AsmVmxSupportDetection
.type AsmVmxSupportDetection, @function
/* ------------------------------------------------------------------------ */
AsmVmxSupportDetection:
push %rbx
push %rcx
push %rdx
xor %eax, %eax
inc %eax
cpuid
xor %rax, %rax
bt $0x05, %ecx
jc VMXSupport
VMXNotSupport:
jmp RetInst
VMXSupport:
mov $0x01, %rax
RetInst:
pop %rdx
pop %rcx
pop %rbx
ret
.size AsmVmxSupportDetection, .-AsmVmxSupportDetection
/* ------------------------------------------------------------------------ */
/* Mark the stack as non-executable (no executable-stack requirement). */
.section .note.GNU-stack,"",@progbits

View file

@ -11,6 +11,11 @@
*/
#include "pch.h"
#ifdef __linux__
# include <sys/stat.h> // struct stat / stat() for IsFileExistA
# include <immintrin.h> // Intel TSX RTM intrinsics (_xbegin/_xend); requires -mrtm
#endif
//
// Global Variables
//
@ -376,62 +381,55 @@ ConvertStringToUInt32(string TextToConvert, PUINT32 Result)
TextToConvert.erase(remove(TextToConvert.begin(), TextToConvert.end(), '`'),
TextToConvert.end());
int Base = IsDecimal ? 10 : 16;
if (IsDecimal)
{
if (!IsDecimalNotation(TextToConvert))
{
return FALSE;
}
else
{
try
{
INT I = std::stoi(TextToConvert);
*Result = I;
return TRUE;
}
catch (std::invalid_argument const &)
{
//
// Bad input: std::invalid_argument thrown
//
return FALSE;
}
catch (std::out_of_range const &)
{
//
// Integer overflow: std::out_of_range thrown
//
return FALSE;
}
return FALSE;
}
}
else
{
//
// It's not decimal
//
if (!IsHexNotation(TextToConvert))
{
return FALSE;
}
else
}
try
{
size_t Pos = 0;
unsigned long long ULL = std::stoull(TextToConvert, &Pos, Base);
//
// Make sure the whole string was consumed and the value
// actually fits into 32 bits (stoull works in 64-bit space,
// so this catches overflow that stoi's signed 32-bit check
// would incorrectly flag or silently mishandle)
//
if (Pos != TextToConvert.size() || ULL > (std::numeric_limits<UINT32>::max)())
{
//
// It's hex number
//
UINT32 TempResult;
TempResult = stoi(TextToConvert, nullptr, 16);
//
// Apply the results
//
*Result = TempResult;
return TRUE;
return FALSE;
}
*Result = static_cast<UINT32>(ULL);
return TRUE;
}
catch (std::invalid_argument const &)
{
//
// Bad input: std::invalid_argument thrown
//
return FALSE;
}
catch (std::out_of_range const &)
{
//
// Integer overflow: std::out_of_range thrown
//
return FALSE;
}
}
@ -510,7 +508,7 @@ CompareLowerCaseStrings(CommandToken TargetToken, const CHAR * StringToCompare)
//
// Convert the token value to 64 bit unsigned integer
//
return _stricmp(TargetTokenValue.c_str(), StringToCompare) == 0;
return PlatformStrCaseCmp(TargetTokenValue.c_str(), StringToCompare) == 0;
}
/**
@ -645,6 +643,7 @@ SetPrivilege(HANDLE Token, // access token handle
BOOL EnablePrivilege // to enable or disable privilege
)
{
#ifdef _WIN32
TOKEN_PRIVILEGES Tp;
LUID Luid;
@ -680,6 +679,16 @@ SetPrivilege(HANDLE Token, // access token handle
}
return TRUE;
#else
//
// TODO(Linux): no Windows access-token/privilege model. This helper has no
// Linux callers today; wire to capabilities (e.g. CAP_SYS_ADMIN) if needed.
//
UNREFERENCED_PARAMETER(Token);
UNREFERENCED_PARAMETER(Privilege);
UNREFERENCED_PARAMETER(EnablePrivilege);
return FALSE;
#endif
}
/**
@ -752,8 +761,17 @@ IsFileExistA(const CHAR * FileName)
BOOLEAN
IsFileExistW(const WCHAR * FileName)
{
#ifdef _WIN32
struct _stat64i32 buffer;
return (_wstat(FileName, &buffer) == 0);
#else
//
// TODO(Linux): blocked on the wide-char (2-byte WCHAR -> UTF-8) conversion
// work; once available, convert FileName and delegate to IsFileExistA.
//
UNREFERENCED_PARAMETER(FileName);
return FALSE;
#endif
}
/**
@ -791,6 +809,7 @@ IsEmptyString(CHAR * Text)
VOID
GetConfigFilePath(PWCHAR ConfigPath)
{
#ifdef _WIN32
WCHAR CurrentPath[MAX_PATH] = {0};
//
@ -807,6 +826,17 @@ GetConfigFilePath(PWCHAR ConfigPath)
// Combine current exe path with config file name
//
PathCombineW(ConfigPath, CurrentPath, CONFIG_FILE_NAME);
#else
//
// TODO(Linux): resolve the executable's directory via readlink("/proc/self/exe")
// and append CONFIG_FILE_NAME. Blocked on the wide-char (2-byte WCHAR) work
// since ConfigPath is a PWCHAR. For now leave the path empty.
//
if (ConfigPath != NULL)
{
ConfigPath[0] = 0;
}
#endif
}
/**
@ -819,6 +849,7 @@ GetConfigFilePath(PWCHAR ConfigPath)
std::vector<std::string>
ListDirectory(const std::string & Directory, const std::string & Extension)
{
#ifdef _WIN32
WIN32_FIND_DATAA FindData;
HANDLE Find = INVALID_HANDLE_VALUE;
std::string FullPath = Directory + "\\" + Extension;
@ -837,6 +868,15 @@ ListDirectory(const std::string & Directory, const std::string & Extension)
FindClose(Find);
return DirList;
#else
//
// TODO(Linux): reimplement with opendir/readdir + fnmatch(Extension) over
// Directory. Only caller today is the script-engine test harness (eval.cpp).
//
UNREFERENCED_PARAMETER(Directory);
UNREFERENCED_PARAMETER(Extension);
return std::vector<std::string>();
#endif
}
/**
@ -920,7 +960,7 @@ ConvertStringVectorToCharPointerArray(const std::string & s)
VOID
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, INT * CpuInfo)
{
CpuIdEx(CpuInfo, Func, SubFunc);
CpuCpuIdEx(CpuInfo, Func, SubFunc);
}
/**

View file

@ -72,7 +72,7 @@ CommandBpPerformApplyingBreakpointOnUserDebugger(DEBUGGEE_BP_PACKET * BpPacket)
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_SET_BREAKPOINT_USER_DEBUGGER, // IO Control Code (IOCTL)
BpPacket, // Input Buffer to driver.
@ -85,7 +85,7 @@ CommandBpPerformApplyingBreakpointOnUserDebugger(DEBUGGEE_BP_PACKET * BpPacket)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}

View file

@ -145,7 +145,7 @@ private:
for (int i = 0; i <= nIds_; ++i)
{
CpuIdEx(cpui.data(), i, 0);
CpuCpuIdEx(cpui.data(), i, 0);
data_.push_back(cpui);
}
@ -197,7 +197,7 @@ private:
for (int i = 0x80000000; i <= nExIds_; ++i)
{
CpuIdEx(cpui.data(), i, 0);
CpuCpuIdEx(cpui.data(), i, 0);
extdata_.push_back(cpui);
}

View file

@ -273,7 +273,7 @@ CommandReadMemoryAndDisassembler(vector<CommandToken> CommandTokens, string Comm
//
// Default process we read from current process
//
Pid = GetCurrentProcessId();
Pid = PlatformGetCurrentProcessId();
}
if (CompareLowerCaseStrings(CommandTokens.at(0), "db"))

View file

@ -118,7 +118,7 @@ WriteMemoryContent(UINT64 AddressToEdit,
//
// Zero the buffer
//
ZeroMemory(FinalBuffer, FinalSize);
PlatformZeroMemory(FinalBuffer, FinalSize);
//
// Copy the structure on top of the allocated buffer
@ -143,7 +143,7 @@ WriteMemoryContent(UINT64 AddressToEdit,
}
else
{
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_EDIT_MEMORY, // IO Control Code (IOCTL)
FinalBuffer, // Input Buffer to driver.
@ -156,7 +156,7 @@ WriteMemoryContent(UINT64 AddressToEdit,
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
free(FinalBuffer);
return FALSE;
}
@ -229,7 +229,7 @@ HyperDbgWriteMemory(PVOID DestinationAddress,
//
// Zero the buffer
//
ZeroMemory(TargetBuffer, FinalSize);
PlatformZeroMemory(TargetBuffer, FinalSize);
//
// Copy requested memory in 64bit chunks
@ -490,7 +490,7 @@ CommandEditMemory(vector<CommandToken> CommandTokens, string Command)
//
if (ProcId == 0)
{
ProcId = GetCurrentProcessId();
ProcId = PlatformGetCurrentProcessId();
}
//
@ -535,7 +535,7 @@ CommandEditMemory(vector<CommandToken> CommandTokens, string Command)
//
// Zero the buffer
//
ZeroMemory(FinalBuffer, FinalSize);
PlatformZeroMemory(FinalBuffer, FinalSize);
//
// Put the values in 64 bit structures

View file

@ -712,7 +712,7 @@ CommandEventsModifyAndQueryEvents(UINT64 Tag,
// Send the request to the kernel
//
Status =
DeviceIoControl(g_DeviceHandle, // Handle to device
PlatformDeviceIoControl(g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_MODIFY_EVENTS, // IO Control Code (IOCTL)
&ModifyEventRequest, // Input Buffer to driver.
SIZEOF_DEBUGGER_MODIFY_EVENTS, // Input buffer length
@ -725,7 +725,7 @@ CommandEventsModifyAndQueryEvents(UINT64 Tag,
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}

View file

@ -63,7 +63,7 @@ CommandFlushRequestFlush()
// want to pass some other arguments to the kernel in
// the future
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_FLUSH_LOGGING_BUFFERS, // IO Control Code (IOCTL)
&FlushRequest, // Input Buffer to driver.
@ -77,7 +77,7 @@ CommandFlushRequestFlush()
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return;
}

View file

@ -48,6 +48,7 @@ CommandLmHelp()
*
* @return wstring
*/
#ifdef _WIN32
std::wstring
CommandLmConvertWow64CompatibilityPaths(const WCHAR * LocalFilePath)
{
@ -72,6 +73,12 @@ CommandLmConvertWow64CompatibilityPaths(const WCHAR * LocalFilePath)
return filePath;
}
#endif // _WIN32
//
// TODO(Linux): no Linux counterpart — the WoW64 system32/SysWOW64 and
// "Program Files (x86)" redirections are NT-specific, and the only caller is
// the user-mode module listing below, which is itself Windows-only for now.
//
/**
* @brief show modules for specified user mode process
@ -83,6 +90,20 @@ CommandLmConvertWow64CompatibilityPaths(const WCHAR * LocalFilePath)
BOOLEAN
CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
{
#ifndef _WIN32
//
// TODO(Linux): the module-name filter converts the search string with
// mbstowcs into a buffer sized for 2-byte WCHAR, which native 4-byte
// wchar_t would overrun, and the listing formats 2-byte WCHAR paths as
// std::wstring. Both need the wide-char item resolved. Stubbed rather than
// cast so no bogus reinterpretation (or heap overrun) can be reached.
//
UNREFERENCED_PARAMETER(ProcessId);
UNREFERENCED_PARAMETER(SearchModule);
ShowMessages("err, listing user-mode modules is not supported on Linux yet\n");
return FALSE;
#else
BOOLEAN Status;
ULONG ReturnedLength;
UINT32 ModuleDetailsSize = 0;
@ -108,7 +129,7 @@ CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
//
// Send the request to the kernel
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_GET_USER_MODE_MODULE_DETAILS, // IO Control
// code
@ -123,7 +144,7 @@ CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}
@ -146,7 +167,7 @@ CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
return FALSE;
}
RtlZeroMemory(ModuleDetailsRequest, ModuleDetailsSize);
PlatformZeroMemory(ModuleDetailsRequest, ModuleDetailsSize);
//
// Set the module details to get the modules (not count)
@ -157,7 +178,7 @@ CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
//
// Send the request to the kernel
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_GET_USER_MODE_MODULE_DETAILS, // IO Control
// code
@ -173,7 +194,7 @@ CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
if (!Status)
{
free(ModuleDetailsRequest);
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}
@ -197,7 +218,7 @@ CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
return FALSE;
}
RtlZeroMemory(WcharBuff, CharSize);
PlatformZeroMemory(WcharBuff, CharSize);
mbstowcs(WcharBuff, SearchModule, CharSize);
@ -263,6 +284,7 @@ CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
ShowErrorMessage(ModuleCountRequest.Result);
return FALSE;
}
#endif // _WIN32
}
/**
@ -274,6 +296,18 @@ CommandLmShowUserModeModule(UINT32 ProcessId, const CHAR * SearchModule)
BOOLEAN
CommandLmShowKernelModeModule(const CHAR * SearchModule)
{
#ifndef _WIN32
//
// TODO(Linux): NT-style system module enumeration (PRTL_PROCESS_MODULES via
// NtQuerySystemInformation) has no Linux analog — same reason
// DebuggerGetNtoskrnlBase is stubbed. Needs a Linux mechanism
// (/proc/modules) once the kernel side exists.
//
UNREFERENCED_PARAMETER(SearchModule);
ShowMessages("err, listing kernel-mode modules is not supported on Linux yet\n");
return FALSE;
#else
PRTL_PROCESS_MODULES ModulesInfo = NULL;
string SearchModuleString;
@ -344,6 +378,7 @@ CommandLmShowKernelModeModule(const CHAR * SearchModule)
free(ModulesInfo);
return TRUE;
#endif // _WIN32
}
/**
@ -483,7 +518,7 @@ CommandLm(vector<CommandToken> CommandTokens, string Command)
}
else
{
CommandLmShowUserModeModule(GetCurrentProcessId(), SearchString);
CommandLmShowUserModeModule(PlatformGetCurrentProcessId(), SearchString);
}
}

View file

@ -87,7 +87,7 @@ CommandLoad(vector<CommandToken> CommandTokens, string Command)
// process (HyperDbg's process) as the base for user-mode
// symbols
//
SymbolLocalReload(GetCurrentProcessId());
SymbolLocalReload(PlatformGetCurrentProcessId());
}
else if (CompareLowerCaseStrings(CommandTokens.at(1), "vmm") ||
CompareLowerCaseStrings(CommandTokens.at(1), "vm"))
@ -120,7 +120,7 @@ CommandLoad(vector<CommandToken> CommandTokens, string Command)
// process (HyperDbg's process) as the base for user-mode
// symbols
//
SymbolLocalReload(GetCurrentProcessId());
SymbolLocalReload(PlatformGetCurrentProcessId());
}
else if (CompareLowerCaseStrings(CommandTokens.at(1), "trace") ||
CompareLowerCaseStrings(CommandTokens.at(1), "hypertrace"))

View file

@ -276,7 +276,7 @@ CommandOutput(vector<CommandToken> CommandTokens, string Command)
return;
}
RtlZeroMemory(EventForwardingObject, sizeof(DEBUGGER_EVENT_FORWARDING));
PlatformZeroMemory(EventForwardingObject, sizeof(DEBUGGER_EVENT_FORWARDING));
//
// Set the state
@ -318,8 +318,9 @@ CommandOutput(vector<CommandToken> CommandTokens, string Command)
//
// Move the name of the output source to the buffer
//
strcpy_s(EventForwardingObject->Name,
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(2)).c_str());
PlatformStrCpy(EventForwardingObject->Name,
sizeof(EventForwardingObject->Name),
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(2)).c_str());
//
// Check if list is initialized or not

View file

@ -33,6 +33,7 @@ CommandRdmsrHelp()
ShowMessages("\t\te.g : rdmsr c0000082 core 2\n");
}
#ifdef _WIN32
/// defines the GetLogicalProcessorInformationEx function
typedef BOOL(WINAPI * glpie_t)(
LOGICAL_PROCESSOR_RELATIONSHIP,
@ -76,7 +77,7 @@ GetWindowsNumaNumberOfCores()
}
GetLogicalProcessorInformationEx(RelationAll, NULL, &Length);
if (Length < 1 || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
if (Length < 1 || PlatformGetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
return 0;
}
@ -107,6 +108,7 @@ GetWindowsNumaNumberOfCores()
free(Buffer);
return NumCores;
}
#endif // _WIN32
/**
* @brief rdmsr command handler
@ -197,17 +199,21 @@ CommandRdmsr(vector<CommandToken> CommandTokens, string Command)
//
// Find logical cores count
//
#ifdef _WIN32
SIZE_T NumCores = GetWindowsNumaNumberOfCores();
NumCPU = NumCores > 0 ? NumCores : GetWindowsCompatibleNumberOfCores();
#else
NumCPU = PlatformGetActiveProcessorCount();
#endif
//
// allocate buffer for transferring messages
//
UINT64 * OutputBuffer = (UINT64 *)malloc(sizeof(UINT64) * NumCPU);
ZeroMemory(OutputBuffer, sizeof(UINT64) * NumCPU);
PlatformZeroMemory(OutputBuffer, sizeof(UINT64) * NumCPU);
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_READ_OR_WRITE_MSR, // IO Control Code (IOCTL)
&MsrReadRequest, // Input Buffer to driver.
@ -221,7 +227,7 @@ CommandRdmsr(vector<CommandToken> CommandTokens, string Command)
if (!Status)
{
ShowMessages("ioctl failed with code (%x), either msr index or core id is invalid\n",
GetLastError());
PlatformGetLastError());
free(OutputBuffer);
return;
}

View file

@ -76,13 +76,13 @@ CommandSearchSendRequest(UINT64 * BufferToSendAsIoctl, UINT32 BufferToSendAsIoct
// Also it's better to Zero the memory; however it's not necessary
// as we zero the buffer in the search routines
//
ZeroMemory(ResultsBuffer, MaximumSearchResults * sizeof(UINT64));
PlatformZeroMemory(ResultsBuffer, MaximumSearchResults * sizeof(UINT64));
//
// Fire the IOCTL
//
Status =
DeviceIoControl(g_DeviceHandle, // Handle to device
PlatformDeviceIoControl(g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_SEARCH_MEMORY, // IO Control Code (IOCTL)
BufferToSendAsIoctl, // Input Buffer to driver.
BufferToSendAsIoctlSize, // Input buffer length
@ -95,7 +95,7 @@ CommandSearchSendRequest(UINT64 * BufferToSendAsIoctl, UINT32 BufferToSendAsIoct
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
free(ResultsBuffer);
return;
@ -394,7 +394,7 @@ CommandSearchMemory(vector<CommandToken> CommandTokens, string Command)
if (ProcId == 0)
{
ProcId = GetCurrentProcessId();
ProcId = PlatformGetCurrentProcessId();
}
//
@ -473,7 +473,7 @@ CommandSearchMemory(vector<CommandToken> CommandTokens, string Command)
//
// Zero the buffer
//
ZeroMemory(FinalBuffer, FinalSize);
PlatformZeroMemory(FinalBuffer, FinalSize);
//
// Copy the structure on top of the allocated buffer

View file

@ -59,6 +59,7 @@ CommandSettingsHelp()
BOOLEAN
CommandSettingsGetValueFromConfigFile(std::string OptionName, std::string & OptionValue)
{
#ifdef _WIN32
inipp::Ini<char> Ini;
WCHAR ConfigPath[MAX_PATH] = {0};
std::string OptionValueFromFile;
@ -101,6 +102,17 @@ CommandSettingsGetValueFromConfigFile(std::string OptionName, std::string & Opti
{
return FALSE;
}
#else
//
// TODO(Linux): the config file is addressed by a wide-char (WCHAR) path and
// read through std::ifstream, which libstdc++ cannot construct from a 2-byte
// WCHAR buffer. GetConfigFilePath() already empties the path on Linux, so this
// always fails. Blocked on the wide-char (2-byte WCHAR) work.
//
UNREFERENCED_PARAMETER(OptionName);
UNREFERENCED_PARAMETER(OptionValue);
return FALSE;
#endif
}
/**
@ -114,6 +126,7 @@ CommandSettingsGetValueFromConfigFile(std::string OptionName, std::string & Opti
VOID
CommandSettingsSetValueFromConfigFile(std::string OptionName, std::string OptionValue)
{
#ifdef _WIN32
inipp::Ini<char> Ini;
WCHAR ConfigPath[MAX_PATH] = {0};
@ -150,6 +163,16 @@ CommandSettingsSetValueFromConfigFile(std::string OptionName, std::string Option
Ini.generate(Os);
Os.close();
#else
//
// TODO(Linux): the config file is addressed by a wide-char (WCHAR) path and
// written through std::ofstream, which libstdc++ cannot construct from a
// 2-byte WCHAR buffer. GetConfigFilePath() already empties the path on Linux,
// so nothing can be persisted. Blocked on the wide-char (2-byte WCHAR) work.
//
UNREFERENCED_PARAMETER(OptionName);
UNREFERENCED_PARAMETER(OptionValue);
#endif
}
/**

View file

@ -61,7 +61,7 @@ CommandTestPerformKernelTestsIoctl()
// want to pass some other arguments to the kernel in
// the future
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PERFORM_KERNEL_SIDE_TESTS, // IO Control Code (IOCTL)
&KernelTestRequest, // Input Buffer to driver.
@ -75,7 +75,7 @@ CommandTestPerformKernelTestsIoctl()
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}
@ -134,6 +134,18 @@ CommandTestAllFunctionalities()
return;
}
if (!OpenHyperDbgTestProcess(&ThreadHandle, &ProcessHandle, (CHAR *)TEST_CASE_PARAMETER_FOR_SCRIPT_FLOATING_POINT))
{
ShowMessages("err, start HyperDbg test process for testing floating-point scripts\n");
return;
}
if (!OpenHyperDbgTestProcess(&ThreadHandle, &ProcessHandle, (CHAR *)TEST_CASE_PARAMETER_FOR_SCRIPT_VARIABLE_TYPES))
{
ShowMessages("err, start HyperDbg test process for testing variable-type scripts\n");
return;
}
//
// Test script engine (script parser) using semantic tests
//
@ -192,7 +204,7 @@ CommandTestPerformTest()
return FALSE;
}
RtlZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
PlatformZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
//
// Create tests process to create a thread for us
@ -233,7 +245,7 @@ SendCommandAndWaitForResponse:
return FALSE;
}
RtlZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
PlatformZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
ReadBytes =
NamedPipeServerReadClientMessage(PipeHandle, (CHAR *)Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);

View file

@ -158,7 +158,7 @@ CommandWrmsr(vector<CommandToken> CommandTokens, string Command)
MsrWriteRequest.CoreNumber = CoreNumer;
MsrWriteRequest.Value = Value;
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_READ_OR_WRITE_MSR, // IO Control Code (IOCTL)
&MsrWriteRequest, // Input Buffer to driver.
@ -172,7 +172,7 @@ CommandWrmsr(vector<CommandToken> CommandTokens, string Command)
if (!Status)
{
ShowMessages("ioctl failed with code (%x), either msr index or core id is invalid\n",
GetLastError());
PlatformGetLastError());
return;
}

View file

@ -69,7 +69,7 @@ CommandApicSendRequest(DEBUGGER_APIC_REQUEST_TYPE ApicType,
return FALSE;
}
RtlZeroMemory(ApicRequest, RequestSize);
PlatformZeroMemory(ApicRequest, RequestSize);
//
// Set the APIC type to local apic
@ -90,7 +90,7 @@ CommandApicSendRequest(DEBUGGER_APIC_REQUEST_TYPE ApicType,
else
{
*IsUsingX2APIC = ApicRequest->IsUsingX2APIC;
RtlCopyMemory(ApicBuffer, (PVOID)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST)), ExpectedRequestSize);
PlatformCopyMemory(ApicBuffer, (PVOID)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST)), ExpectedRequestSize);
free(ApicRequest);
return TRUE;
@ -103,7 +103,7 @@ CommandApicSendRequest(DEBUGGER_APIC_REQUEST_TYPE ApicType,
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PERFORM_ACTIONS_ON_APIC, // IO Control Code (IOCTL)
ApicRequest, // Input Buffer to driver.
@ -116,7 +116,7 @@ CommandApicSendRequest(DEBUGGER_APIC_REQUEST_TYPE ApicType,
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
free(ApicRequest);
return FALSE;
@ -139,7 +139,7 @@ CommandApicSendRequest(DEBUGGER_APIC_REQUEST_TYPE ApicType,
// Fill the request buffer
//
*IsUsingX2APIC = ApicRequest->IsUsingX2APIC;
RtlCopyMemory(ApicBuffer, (PVOID)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST)), ExpectedRequestSize);
PlatformCopyMemory(ApicBuffer, (PVOID)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST)), ExpectedRequestSize);
free(ApicRequest);
return TRUE;

View file

@ -32,6 +32,7 @@ CommandEptHookHelp()
ShowMessages("\t\te.g : !epthook fffff801deadb000\n");
ShowMessages("\t\te.g : !epthook fffff801deadb000 pid 400\n");
ShowMessages("\t\te.g : !epthook fffff801deadb000 core 2 pid 400\n");
ShowMessages("\t\te.g : !epthook nt!ExAllocatePoolWithTag script { printf(\"hook triggered at: %%llx\\n\", $context); }\n");
ShowMessages("\t\te.g : !epthook fffff801deadb000 script { printf(\"hook triggered at: %%llx\\n\", $context); }\n");
ShowMessages("\t\te.g : !epthook fffff801deadb000 asm code { nop; nop; nop }\n");
}

View file

@ -299,7 +299,7 @@ HyperDbgEnableTransparentModeEx(UINT32 ProcessId, CHAR * ProcessName, BOOLEAN Is
//
// Zero the memory
//
RtlZeroMemory(FinalRequestBuffer, RequestBufferSize);
PlatformZeroMemory(FinalRequestBuffer, RequestBufferSize);
//
// Copy the buffer on the top of the final buffer
@ -322,7 +322,7 @@ HyperDbgEnableTransparentModeEx(UINT32 ProcessId, CHAR * ProcessName, BOOLEAN Is
//
// Send the request to the kernel
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_HIDE_AND_UNHIDE_TO_TRANSPARENT_THE_DEBUGGER, // IO Control
// code
@ -337,7 +337,7 @@ HyperDbgEnableTransparentModeEx(UINT32 ProcessId, CHAR * ProcessName, BOOLEAN Is
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
free(FinalRequestBuffer);
return FALSE;
}

View file

@ -69,7 +69,7 @@ HyperDbgGetIdtEntry(INTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS * IdtPacket)
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_QUERY_IDT_ENTRY, // IO Control Code (IOCTL)
IdtPacket, // Input Buffer to driver.
@ -82,7 +82,7 @@ HyperDbgGetIdtEntry(INTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS * IdtPacket)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}
@ -164,7 +164,7 @@ CommandIdt(vector<CommandToken> CommandTokens, string Command)
ShowMessages("err, allocating buffer for receiving IDT entries");
}
RtlZeroMemory(IdtPacket, sizeof(INTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS));
PlatformZeroMemory(IdtPacket, sizeof(INTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS));
//
// Get the IDT buffer

View file

@ -214,7 +214,7 @@ CommandIoapic(vector<CommandToken> CommandTokens, string Command)
ShowMessages("err, allocating buffer for receiving I/O APIC");
}
RtlZeroMemory(IoApicPackets, sizeof(IO_APIC_ENTRY_PACKETS));
PlatformZeroMemory(IoApicPackets, sizeof(IO_APIC_ENTRY_PACKETS));
//
// Get the I/O APIC buffer

View file

@ -63,7 +63,8 @@ CommandLbrHelp()
ShowMessages("\t or the 'kernel'. it prevents all types of branches except calls and rets\n");
ShowMessages("\t (no option): capture everything (default option)\n");
ShowMessages("\nnote 1: LBR is usually not supported (or is emulated) in nested virtualization (VM) environments\n");
ShowMessages("\n");
ShowMessages("note 1: LBR is usually not supported (or is emulated) in nested virtualization (VM) environments\n");
ShowMessages("note 2: LBR will be disabled if there is a debug-break (#DB) condition, such as the trap flags or\n");
ShowMessages(" hardware debug registers (to learn how to mitigate this, check the documentation)\n");
}
@ -86,7 +87,7 @@ CommandLbrSendRequest(HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest)
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PERFORM_HYPERTRACE_LBR_OPERATION, // IO Control Code (IOCTL)
LbrRequest, // Input Buffer to driver.
@ -99,7 +100,7 @@ CommandLbrSendRequest(HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}
@ -328,7 +329,7 @@ CommandLbrShowSuccessMessage(const HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest
VOID
CommandLbr(vector<CommandToken> CommandTokens, string Command)
{
HYPERTRACE_LBR_OPERATION_PACKETS LbrRequest = {0};
HYPERTRACE_LBR_OPERATION_PACKETS LbrRequest = {};
BOOLEAN ParseResult = FALSE;
if (CommandTokens.size() == 1)

View file

@ -48,7 +48,7 @@ HyperDbgLbrdumpSendRequest(HYPERTRACE_LBR_DUMP_PACKETS * LbrdumpRequest)
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PERFORM_HYPERTRACE_LBR_DUMP, // IO Control Code (IOCTL)
LbrdumpRequest, // Input Buffer to driver.
@ -61,7 +61,7 @@ HyperDbgLbrdumpSendRequest(HYPERTRACE_LBR_DUMP_PACKETS * LbrdumpRequest)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}
@ -239,7 +239,7 @@ CommandLbrdumpPrint(HYPERTRACE_LBR_DUMP_PACKETS * LbrdumpRequest)
VOID
CommandLbrdump(vector<CommandToken> CommandTokens, string Command)
{
HYPERTRACE_LBR_DUMP_PACKETS LbrdumpRequest = {0};
HYPERTRACE_LBR_DUMP_PACKETS LbrdumpRequest = {};
UINT32 CoreId = 0;
BOOLEAN ContinueDumpingAllCores = TRUE;

View file

@ -168,14 +168,14 @@ CommandPa2va(vector<CommandToken> CommandTokens, string Command)
if (Pid == 0)
{
Pid = GetCurrentProcessId();
Pid = PlatformGetCurrentProcessId();
AddressDetails.ProcessId = Pid;
}
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_VA2PA_AND_PA2VA_COMMANDS, // IO Control Code (IOCTL)
&AddressDetails, // Input Buffer to driver.
@ -189,7 +189,7 @@ CommandPa2va(vector<CommandToken> CommandTokens, string Command)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return;
}

View file

@ -48,7 +48,7 @@ CommandPcicam(vector<CommandToken> CommandTokens, string Command)
{
BOOL Status;
ULONG ReturnedLength;
DEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET PcidevinfoPacket = {0};
DEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET PcidevinfoPacket = {};
UINT32 TargetBus = 0;
UINT32 TargetDevice = 0;
UINT32 TargetFunction = 0;
@ -128,7 +128,7 @@ CommandPcicam(vector<CommandToken> CommandTokens, string Command)
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PCIDEVINFO_ENUM, // IO Control Code (IOCTL)
&PcidevinfoPacket, // Input Buffer to driver.
@ -142,7 +142,7 @@ CommandPcicam(vector<CommandToken> CommandTokens, string Command)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return;
}

View file

@ -46,7 +46,7 @@ CommandPcitree(vector<CommandToken> CommandTokens, string Command)
{
BOOL Status;
ULONG ReturnedLength;
DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreePacket = {0};
DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreePacket = {};
if (CommandTokens.size() != 1)
{
@ -70,7 +70,7 @@ CommandPcitree(vector<CommandToken> CommandTokens, string Command)
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PCIE_ENDPOINT_ENUM, // IO Control Code (IOCTL)
&PcitreePacket, // Input Buffer to driver.
@ -84,7 +84,7 @@ CommandPcitree(vector<CommandToken> CommandTokens, string Command)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return;
}

View file

@ -0,0 +1,119 @@
/**
* @file pt-linux.cpp
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief Linux stub implementations of the !pt (Intel Processor Trace) command (pt.cpp)
* @details The Windows implementation (pt.cpp) drives Intel PT by attaching to a
* live process, so it is built almost entirely out of Win32
* process/thread management roughly 27 raw Win32 call sites, with no
* #ifdef guards anywhere in the file:
* - CreateToolhelp32Snapshot + Process32First/Next and
* Thread32First/Next to walk processes and threads by name/pid/tid,
* - OpenProcess / OpenThread plus the handle lifetime around them
* (CloseHandle x8),
* - SetThreadAffinityMask to pin the traced thread to a core,
* - CreateEvent / CreateThread / WaitForMultipleObjects for the
* background trace thread and its g_PtTraceStopEvent stop signal,
* - two DeviceIoControl + GetLastError pairs.
*
* Those last two are simple renames onto the existing Platform*
* wrappers, but everything above needs a real decision per call site
* either route it through a new cross-platform wrapper, or guard the
* whole enclosing function for Windows and give Linux a stub because
* the Win32 calls are interleaved with the surrounding walk and UI
* logic rather than sitting behind a clean boundary. Porting half the
* file would leave it in a worse state than leaving it whole, so until
* that work is done the entire translation unit is swapped out on Linux
* (CMake `if(UNIX)` REMOVE_ITEM pt.cpp + APPEND pt-linux.cpp). This
* mirrors how symbol.cpp, pe-parser.cpp, install.cpp and namedpipe.cpp
* are handled; pt.cpp itself is left 100% untouched for the Windows
* build.
*
* Only the 4 externally visible functions are provided here CommandPt
* and CommandPtHelp (declared in commands.h / help.h, reached from the
* command dispatch table) and HyperDbgPerformPtOperation /
* HyperDbgPtMmapSendRequest (declared in debugger.h). Everything else
* in pt.cpp is helper code reached only through those entry points, so
* it simply does not exist in the Linux translation unit.
*
* TODO(Linux) to make these real: the Toolhelp process/thread walks
* become /proc enumeration, OpenProcess/OpenThread become pid/tid
* handles (or a ptrace attach), SetThreadAffinityMask becomes
* sched_setaffinity(2), and the event/thread machinery becomes the
* existing Platform* wrappers. Note the underlying IOCTL transport
* (platform-ioctl) is itself still a Linux stub, so a working !pt also
* depends on the kernel module landing.
*
* @version 0.1
* @date 2026-07-24
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
#ifdef __linux__
/**
* @brief help of the !pt command
*
* @return VOID
*/
VOID
CommandPtHelp()
{
ShowMessages("!pt : enables, disables and configures Intel Processor Trace (PT).\n\n");
ShowMessages("err, the !pt command is not supported on Linux yet\n");
}
/**
* @brief !pt command handler
*
* @param CommandTokens
* @param Command
*
* @return VOID
*/
VOID
CommandPt(vector<CommandToken> CommandTokens, string Command)
{
UNREFERENCED_PARAMETER(CommandTokens);
UNREFERENCED_PARAMETER(Command);
ShowMessages("err, the !pt command is not supported on Linux yet\n");
}
/**
* @brief Send an Intel PT operation request to the kernel
*
* @param PtRequest
*
* @return BOOLEAN
*/
BOOLEAN
HyperDbgPerformPtOperation(HYPERTRACE_PT_OPERATION_PACKETS * PtRequest)
{
UNREFERENCED_PARAMETER(PtRequest);
ShowMessages("err, Intel PT operations are not supported on Linux yet\n");
return FALSE;
}
/**
* @brief Send an Intel PT trace-buffer mapping request to the kernel
*
* @param MmapRequest
*
* @return BOOLEAN
*/
BOOLEAN
HyperDbgPtMmapSendRequest(HYPERTRACE_PT_MMAP_PACKETS * MmapRequest)
{
UNREFERENCED_PARAMETER(MmapRequest);
ShowMessages("err, Intel PT buffer mapping is not supported on Linux yet\n");
return FALSE;
}
#endif // __linux__

View file

@ -211,14 +211,14 @@ CommandPte(vector<CommandToken> CommandTokens, string Command)
if (Pid == 0)
{
Pid = GetCurrentProcessId();
Pid = PlatformGetCurrentProcessId();
AddressDetails.ProcessId = Pid;
}
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS, // IO Control Code (IOCTL)
&AddressDetails, // Input Buffer to driver.
@ -232,7 +232,7 @@ CommandPte(vector<CommandToken> CommandTokens, string Command)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return;
}

View file

@ -69,7 +69,7 @@ CommandSmiSendRequest(SMI_OPERATION_PACKETS * SmiOperationRequest)
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PERFORM_SMI_OPERATION, // IO Control Code (IOCTL)
SmiOperationRequest, // Input Buffer to driver.
@ -82,7 +82,7 @@ CommandSmiSendRequest(SMI_OPERATION_PACKETS * SmiOperationRequest)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}
@ -122,7 +122,7 @@ HyperDbgPerformSmiOperation(SMI_OPERATION_PACKETS * SmiOperation)
VOID
CommandSmi(vector<CommandToken> CommandTokens, string Command)
{
SMI_OPERATION_PACKETS SmiOperationRequest = {0};
SMI_OPERATION_PACKETS SmiOperationRequest = {};
if (CommandTokens.size() != 2)
{

View file

@ -57,7 +57,7 @@ HyperDbgDisableTransparentMode()
//
// Send the request to the kernel
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_HIDE_AND_UNHIDE_TO_TRANSPARENT_THE_DEBUGGER, // IO Control
// code
@ -72,7 +72,7 @@ HyperDbgDisableTransparentMode()
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return FALSE;
}

View file

@ -169,14 +169,14 @@ CommandVa2pa(vector<CommandToken> CommandTokens, string Command)
if (Pid == 0)
{
Pid = GetCurrentProcessId();
Pid = PlatformGetCurrentProcessId();
AddressDetails.ProcessId = Pid;
}
//
// Send IOCTL
//
Status = DeviceIoControl(
Status = PlatformDeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_DEBUGGER_VA2PA_AND_PA2VA_COMMANDS, // IO Control Code (IOCTL)
&AddressDetails, // Input Buffer to driver.
@ -190,7 +190,7 @@ CommandVa2pa(vector<CommandToken> CommandTokens, string Command)
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError());
return;
}

View file

@ -58,22 +58,22 @@ CommandDebugHelp()
BOOLEAN
CommandDebugCheckComPort(const CHAR * ComPort, UINT32 * Port)
{
if (_stricmp(ComPort, "com1") == 0)
if (PlatformStrCaseCmp(ComPort, "com1") == 0)
{
*Port = COM1_PORT;
return TRUE;
}
else if (_stricmp(ComPort, "com2") == 0)
else if (PlatformStrCaseCmp(ComPort, "com2") == 0)
{
*Port = COM2_PORT;
return TRUE;
}
else if (_stricmp(ComPort, "com3") == 0)
else if (PlatformStrCaseCmp(ComPort, "com3") == 0)
{
*Port = COM3_PORT;
return TRUE;
}
else if (_stricmp(ComPort, "com4") == 0)
else if (PlatformStrCaseCmp(ComPort, "com4") == 0)
{
*Port = COM4_PORT;
return TRUE;

View file

@ -85,9 +85,9 @@ CommandDisconnect(vector<CommandToken> CommandTokens, string Command)
// We should kill the thread that was listening for the
// remote commands and close the connection
//
TerminateThread(g_RemoteDebuggeeListeningThread, 0);
CloseHandle(g_RemoteDebuggeeListeningThread);
CloseHandle(g_EndOfMessageReceivedEvent);
PlatformTerminateThread(g_RemoteDebuggeeListeningThread, 0);
PlatformCloseHandle(g_RemoteDebuggeeListeningThread);
PlatformCloseHandle(g_EndOfMessageReceivedEvent);
g_EndOfMessageReceivedEvent = NULL;
RemoteConnectionCloseTheConnectionWithDebuggee();

View file

@ -179,7 +179,7 @@ CommandSym(vector<CommandToken> CommandTokens, string Command)
}
else
{
UserProcessId = GetCurrentProcessId();
UserProcessId = PlatformGetCurrentProcessId();
}
}

View file

@ -142,7 +142,7 @@ ForwardingCloseOutputSource(PDEBUGGER_EVENT_FORWARDING SourceDescriptor)
//
// Close the handle
//
CloseHandle(SourceDescriptor->Handle);
PlatformCloseFile(SourceDescriptor->Handle);
//
// Return the status
@ -183,7 +183,7 @@ ForwardingCloseOutputSource(PDEBUGGER_EVENT_FORWARDING SourceDescriptor)
//
// Free the library
//
FreeLibrary(SourceDescriptor->Module);
PlatformFreeLibrary(SourceDescriptor->Module);
//
// Return the status
@ -226,7 +226,7 @@ ForwardingCreateOutputSource(DEBUGGER_EVENT_FORWARDING_TYPE SourceType,
//
// Create a new file
//
HANDLE FileHandle = CreateFileA(Description.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE FileHandle = PlatformOpenFileForWritingNarrow(Description.c_str());
//
// The handle might be INVALID_HANDLE_VALUE which will be
@ -236,7 +236,7 @@ ForwardingCreateOutputSource(DEBUGGER_EVENT_FORWARDING_TYPE SourceType,
}
else if (SourceType == EVENT_FORWARDING_MODULE)
{
HMODULE ModuleHandle = LoadLibraryA(Description.c_str());
HMODULE ModuleHandle = PlatformLoadLibrary(Description.c_str());
if (ModuleHandle == NULL)
{
@ -244,7 +244,7 @@ ForwardingCreateOutputSource(DEBUGGER_EVENT_FORWARDING_TYPE SourceType,
return INVALID_HANDLE_VALUE;
}
hyperdbg_event_forwarding_t hyperdbg_event_forwarding = (hyperdbg_event_forwarding_t)GetProcAddress(ModuleHandle, "hyperdbg_event_forwarding");
hyperdbg_event_forwarding_t hyperdbg_event_forwarding = (hyperdbg_event_forwarding_t)PlatformGetProcAddress(ModuleHandle, "hyperdbg_event_forwarding");
if (hyperdbg_event_forwarding == NULL)
{
@ -503,11 +503,9 @@ ForwardingWriteToFile(HANDLE FileHandle, CHAR * Message, UINT32 MessageLength)
DWORD BytesWritten = 0;
BOOL ErrorFlag = FALSE;
ErrorFlag = WriteFile(FileHandle, // open file handle
Message, // start of data to write
MessageLength, // number of bytes to write
&BytesWritten, // number of bytes that were written
NULL); // no overlapped structure
ErrorFlag = PlatformWriteFile(FileHandle, // open file handle
Message, // start of data to write
MessageLength); // number of bytes to write
return TRUE;

View file

@ -0,0 +1,179 @@
/**
* @file namedpipe-linux.cpp
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief Linux stub implementations of the named-pipe transport (namedpipe.cpp)
* @details The Windows implementation (namedpipe.cpp) is a thin wrapper over the
* Win32 named-pipe IPC API: the server side uses
* CreateNamedPipe/ConnectNamedPipe/ReadFile/WriteFile, and the client
* side uses CreateFileA against the "\\.\pipe\..." name plus overlapped
* ReadFile/WriteFile with the g_OverlappedIoStructureFor*Debugger
* events. None of that maps 1:1 onto Linux, so the whole translation
* unit is swapped out on Linux (CMake `if(UNIX)` REMOVE_ITEM
* namedpipe.cpp + APPEND namedpipe-linux.cpp), mirroring the
* symbol.cpp -> symbol-linux.cpp / pe-parser.cpp -> pe-parser-linux.cpp
* / install.cpp -> install-linux.cpp pattern. namedpipe.cpp itself is
* left 100% untouched for the Windows build. Only the 10 public
* functions declared in namedpipe.h are provided here; the two internal
* *Example() demo functions are not part of the interface and simply do
* not exist in the Linux TU.
*
* The Create* entry points return INVALID_HANDLE_VALUE, so every caller
* bails before reaching the send/read/close paths those stay silent to
* avoid spamming a message on each loop iteration; only the Create*
* functions emit the "not supported" note.
*
* TODO(Linux) to make these real: back the transport with either a
* filesystem FIFO (mkfifo(3), matching the "named pipe" naming most
* closely) or, more usefully for bidirectional message framing, a Unix
* domain socket (AF_UNIX, socket/bind/listen/accept on the server side,
* socket/connect on the client side) whose path is derived from the
* "\\.\pipe\NAME" string. The overlapped/event machinery collapses to
* plain blocking read()/write() (or poll()) since a dedicated thread
* already owns each direction.
*
* @version 0.1
* @date 2026-07-22
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
#ifdef __linux__
////////////////////////////////////////////////////////////////////////////
// Server Side //
////////////////////////////////////////////////////////////////////////////
/**
* @brief Create a named-pipe server endpoint.
* @return HANDLE INVALID_HANDLE_VALUE named pipes are not supported on Linux
* yet (see file header for the FIFO / AF_UNIX plan).
*/
HANDLE
NamedPipeServerCreatePipe(LPCSTR PipeName, UINT32 OutputBufferSize, UINT32 InputBufferSize)
{
UNREFERENCED_PARAMETER(PipeName);
UNREFERENCED_PARAMETER(OutputBufferSize);
UNREFERENCED_PARAMETER(InputBufferSize);
ShowMessages("err, named-pipe communication is not supported on Linux yet\n");
return INVALID_HANDLE_VALUE;
}
/**
* @brief Wait for a client to connect to the server pipe.
* @return BOOLEAN FALSE not supported on Linux yet.
*/
BOOLEAN
NamedPipeServerWaitForClientConntection(HANDLE PipeHandle)
{
UNREFERENCED_PARAMETER(PipeHandle);
return FALSE;
}
/**
* @brief Read a message sent by the connected client.
* @return UINT32 0 not supported on Linux yet.
*/
UINT32
NamedPipeServerReadClientMessage(HANDLE PipeHandle, CHAR * BufferToSave, INT MaximumReadBufferLength)
{
UNREFERENCED_PARAMETER(PipeHandle);
UNREFERENCED_PARAMETER(BufferToSave);
UNREFERENCED_PARAMETER(MaximumReadBufferLength);
return 0;
}
/**
* @brief Send a message to the connected client.
* @return BOOLEAN FALSE not supported on Linux yet.
*/
BOOLEAN
NamedPipeServerSendMessageToClient(HANDLE PipeHandle,
CHAR * BufferToSend,
INT BufferSize)
{
UNREFERENCED_PARAMETER(PipeHandle);
UNREFERENCED_PARAMETER(BufferToSend);
UNREFERENCED_PARAMETER(BufferSize);
return FALSE;
}
/**
* @brief Close the server pipe handle.
* @return VOID no-op not supported on Linux yet.
*/
VOID
NamedPipeServerCloseHandle(HANDLE PipeHandle)
{
UNREFERENCED_PARAMETER(PipeHandle);
}
////////////////////////////////////////////////////////////////////////////
// Client Side //
////////////////////////////////////////////////////////////////////////////
/**
* @brief Connect to a named-pipe server endpoint.
* @return HANDLE INVALID_HANDLE_VALUE not supported on Linux yet.
*/
HANDLE
NamedPipeClientCreatePipe(LPCSTR PipeName)
{
UNREFERENCED_PARAMETER(PipeName);
ShowMessages("err, named-pipe communication is not supported on Linux yet\n");
return INVALID_HANDLE_VALUE;
}
/**
* @brief Connect to a named-pipe server endpoint using overlapped I/O.
* @return HANDLE INVALID_HANDLE_VALUE not supported on Linux yet.
*/
HANDLE
NamedPipeClientCreatePipeOverlappedIo(LPCSTR PipeName)
{
UNREFERENCED_PARAMETER(PipeName);
ShowMessages("err, named-pipe communication is not supported on Linux yet\n");
return INVALID_HANDLE_VALUE;
}
/**
* @brief Send a message to the server over the client pipe.
* @return BOOLEAN FALSE not supported on Linux yet.
*/
BOOLEAN
NamedPipeClientSendMessage(HANDLE PipeHandle, CHAR * BufferToSend, INT BufferSize)
{
UNREFERENCED_PARAMETER(PipeHandle);
UNREFERENCED_PARAMETER(BufferToSend);
UNREFERENCED_PARAMETER(BufferSize);
return FALSE;
}
/**
* @brief Read a message from the server over the client pipe.
* @return UINT32 0 not supported on Linux yet.
*/
UINT32
NamedPipeClientReadMessage(HANDLE PipeHandle, CHAR * BufferToRead, INT MaximumSizeOfBuffer)
{
UNREFERENCED_PARAMETER(PipeHandle);
UNREFERENCED_PARAMETER(BufferToRead);
UNREFERENCED_PARAMETER(MaximumSizeOfBuffer);
return 0;
}
/**
* @brief Close the client pipe handle.
* @return VOID no-op not supported on Linux yet.
*/
VOID
NamedPipeClientClosePipe(HANDLE PipeHandle)
{
UNREFERENCED_PARAMETER(PipeHandle);
}
#endif // __linux__

View file

@ -134,7 +134,7 @@ RemoteConnectionListen(PCSTR Port)
//
// Zero the buffer for next command
//
RtlZeroMemory(recvbuf, COMMUNICATION_BUFFER_SIZE);
PlatformZeroMemory(recvbuf, COMMUNICATION_BUFFER_SIZE);
while (true)
{
@ -175,7 +175,7 @@ RemoteConnectionListen(PCSTR Port)
//
// Zero the buffer for next command
//
RtlZeroMemory(recvbuf, COMMUNICATION_BUFFER_SIZE);
PlatformZeroMemory(recvbuf, COMMUNICATION_BUFFER_SIZE);
}
//
@ -271,13 +271,13 @@ RemoteConnectionThreadListeningToDebuggee(LPVOID lpParam)
//
// Trigger the event
//
SetEvent(g_EndOfMessageReceivedEvent);
PlatformSetEvent(g_EndOfMessageReceivedEvent);
}
//
// Clear the buffer
//
RtlZeroMemory(RecvBuf, COMMUNICATION_BUFFER_SIZE);
PlatformZeroMemory(RecvBuf, COMMUNICATION_BUFFER_SIZE);
}
//
@ -314,7 +314,6 @@ RemoteConnectionThreadListeningToDebuggee(LPVOID lpParam)
VOID
RemoteConnectionConnect(PCSTR Ip, PCSTR Port)
{
DWORD ThreadId;
CHAR Recv[3] = {0};
UINT32 BuffRecv = 0;
@ -412,7 +411,7 @@ RemoteConnectionConnect(PCSTR Ip, PCSTR Port)
//
if (g_EndOfMessageReceivedEvent == NULL)
{
g_EndOfMessageReceivedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
g_EndOfMessageReceivedEvent = PlatformCreateEvent(FALSE, FALSE);
}
//
@ -420,13 +419,9 @@ RemoteConnectionConnect(PCSTR Ip, PCSTR Port)
// the remote debuggee for new messages
// Listen for upcoming messages
//
g_RemoteDebuggeeListeningThread = CreateThread(
NULL,
0,
g_RemoteDebuggeeListeningThread = PlatformCreateThread(
RemoteConnectionThreadListeningToDebuggee,
NULL,
0,
&ThreadId);
NULL);
ShowMessages("connected to %s:%s\n", Ip, Port);
}
@ -458,7 +453,7 @@ RemoteConnectionSendCommand(const CHAR * sendbuf, INT len)
//
// We wait for the debuggee to send the message
//
WaitForSingleObject(
PlatformWaitForSingleObject(
g_EndOfMessageReceivedEvent,
INFINITE);

View file

@ -22,7 +22,6 @@
INT
CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketArg)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL, *ptr = NULL, hints;
INT IResult;
@ -30,14 +29,14 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
//
// Initialize Winsock
//
IResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
IResult = PlatformSocketInitialize();
if (IResult != 0)
{
ShowMessages("err, WSAStartup failed (%x)\n", IResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
PlatformZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
@ -49,7 +48,7 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
if (IResult != 0)
{
ShowMessages("getaddrinfo failed (%x)\n", IResult);
WSACleanup();
PlatformSocketCleanup();
return 1;
}
@ -64,8 +63,8 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET)
{
ShowMessages("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
ShowMessages("socket failed with error: %ld\n", PlatformGetSocketError());
PlatformSocketCleanup();
return 1;
}
@ -75,7 +74,7 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
IResult = connect(ConnectSocket, ptr->ai_addr, (INT)ptr->ai_addrlen);
if (IResult == SOCKET_ERROR)
{
closesocket(ConnectSocket);
PlatformCloseSocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
@ -87,7 +86,7 @@ CommunicationClientConnectToServer(PCSTR Ip, PCSTR Port, SOCKET * ConnectSocketA
if (ConnectSocket == INVALID_SOCKET)
{
ShowMessages("unable to connect to the server\n");
WSACleanup();
PlatformSocketCleanup();
return 1;
}
@ -118,9 +117,9 @@ CommunicationClientSendMessage(SOCKET ConnectSocket, const CHAR * sendbuf, INT b
IResult = send(ConnectSocket, sendbuf, buflen, 0);
if (IResult == SOCKET_ERROR)
{
ShowMessages("err, send failed (%x)\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
ShowMessages("err, send failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ConnectSocket);
PlatformSocketCleanup();
return 1;
}
@ -141,7 +140,7 @@ CommunicationClientShutdownConnection(SOCKET ConnectSocket)
//
// shutdown the connection since no more data will be sent
//
IResult = shutdown(ConnectSocket, SD_SEND);
IResult = PlatformShutdownSocketSend(ConnectSocket);
if (IResult == SOCKET_ERROR)
{
//
@ -150,11 +149,11 @@ CommunicationClientShutdownConnection(SOCKET ConnectSocket)
//
/*
ShowMessages("err, shutdown failed (%x)\n", WSAGetLastError());
ShowMessages("err, shutdown failed (%x)\n", PlatformGetSocketError());
*/
closesocket(ConnectSocket);
WSACleanup();
PlatformCloseSocket(ConnectSocket);
PlatformSocketCleanup();
return 1;
}
return 0;
@ -197,7 +196,7 @@ CommunicationClientReceiveMessage(SOCKET ConnectSocket, CHAR * RecvBuf, UINT32 M
}
else
{
ShowMessages("\nrecv failed with error: %d\n", WSAGetLastError());
ShowMessages("\nrecv failed with error: %d\n", PlatformGetSocketError());
ShowMessages("the remote system closes the connection.\n\n");
return 1;
@ -218,8 +217,8 @@ CommunicationClientCleanup(SOCKET ConnectSocket)
//
// cleanup
//
closesocket(ConnectSocket);
WSACleanup();
PlatformCloseSocket(ConnectSocket);
PlatformSocketCleanup();
return 0;
}

View file

@ -32,8 +32,7 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
SOCKET * ClientSocketArg,
SOCKET * ListenSocketArg)
{
WSADATA wsaData;
INT IResult;
INT IResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
@ -44,14 +43,14 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
//
// Initialize Winsock
//
IResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
IResult = PlatformSocketInitialize();
if (IResult != 0)
{
ShowMessages("err, WSAStartup failed (%x)\n", IResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
PlatformZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
@ -64,7 +63,7 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
if (IResult != 0)
{
ShowMessages("err, getaddrinfo failed (%x)\n", IResult);
WSACleanup();
PlatformSocketCleanup();
return 1;
}
@ -75,9 +74,9 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
ShowMessages("socket failed with error: %ld\n", WSAGetLastError());
ShowMessages("socket failed with error: %ld\n", PlatformGetSocketError());
freeaddrinfo(result);
WSACleanup();
PlatformSocketCleanup();
return 1;
}
@ -87,10 +86,10 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
IResult = ::bind(ListenSocket, result->ai_addr, (INT)result->ai_addrlen);
if (IResult == SOCKET_ERROR)
{
ShowMessages("err, bind failed (%x)\n", WSAGetLastError());
ShowMessages("err, bind failed (%x)\n", PlatformGetSocketError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
PlatformCloseSocket(ListenSocket);
PlatformSocketCleanup();
return 1;
}
@ -99,25 +98,25 @@ CommunicationServerCreateServerAndWaitForClient(PCSTR Port,
IResult = listen(ListenSocket, SOMAXCONN);
if (IResult == SOCKET_ERROR)
{
ShowMessages("err, listen failed (%x)\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
ShowMessages("err, listen failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ListenSocket);
PlatformSocketCleanup();
return 1;
}
//
// Accept a client socket
//
sockaddr_in name = {0};
INT AddrLen = sizeof(name);
sockaddr_in name = {0};
PLATFORM_SOCKLEN AddrLen = sizeof(name);
ClientSocket = accept(ListenSocket, (struct sockaddr *)&name, &AddrLen);
if (ClientSocket == INVALID_SOCKET)
{
ShowMessages("err, accept failed (%x)\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
ShowMessages("err, accept failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ListenSocket);
PlatformSocketCleanup();
return 1;
}
@ -166,9 +165,9 @@ CommunicationServerReceiveMessage(SOCKET ClientSocket, CHAR * recvbuf, INT recvb
}
else
{
ShowMessages("err, recv failed (%x)\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
ShowMessages("err, recv failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ClientSocket);
PlatformSocketCleanup();
return 1;
}
@ -196,9 +195,9 @@ CommunicationServerSendMessage(SOCKET ClientSocket, const CHAR * sendbuf, INT le
if (ISendResult == SOCKET_ERROR)
{
/*
ShowMessages("err, send failed (%x)\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
ShowMessages("err, send failed (%x)\n", PlatformGetSocketError());
PlatformCloseSocket(ClientSocket);
PlatformSocketCleanup();
*/
return 1;
}
@ -221,12 +220,12 @@ CommunicationServerShutdownAndCleanupConnection(SOCKET ClientSocket,
//
// No longer need server socket
//
closesocket(ListenSocket);
PlatformCloseSocket(ListenSocket);
//
// shutdown the connection since we're done
//
IResult = shutdown(ClientSocket, SD_SEND);
IResult = PlatformShutdownSocketSend(ClientSocket);
if (IResult == SOCKET_ERROR)
{
//
@ -235,19 +234,19 @@ CommunicationServerShutdownAndCleanupConnection(SOCKET ClientSocket,
//
/*
ShowMessages("err, shutdown failed (%x)\n", WSAGetLastError());
ShowMessages("err, shutdown failed (%x)\n", PlatformGetSocketError());
*/
closesocket(ClientSocket);
WSACleanup();
PlatformCloseSocket(ClientSocket);
PlatformSocketCleanup();
return 1;
}
//
// cleanup
//
closesocket(ClientSocket);
WSACleanup();
PlatformCloseSocket(ClientSocket);
PlatformSocketCleanup();
return 0;
}

View file

@ -1420,6 +1420,9 @@ InitializeCommandsDictionary()
g_CommandsList["flush"] = {&CommandFlush, &CommandFlushHelp, DEBUGGER_COMMAND_FLUSH_ATTRIBUTES};
g_CommandsList["ucpuid"] = {&CommandUserCpuid, &CommandUserCpuidHelp, DEBUGGER_COMMAND_USER_CPUID_ATTRIBUTES};
g_CommandsList["cpuid"] = {&CommandUserCpuid, &CommandUserCpuidHelp, DEBUGGER_COMMAND_USER_CPUID_ATTRIBUTES};
g_CommandsList["pause"] = {&CommandPause, &CommandPauseHelp, DEBUGGER_COMMAND_PAUSE_ATTRIBUTES};
g_CommandsList[".pause"] = {&CommandPause, &CommandPauseHelp, DEBUGGER_COMMAND_PAUSE_ATTRIBUTES};

View file

@ -1,6 +1,6 @@
/**
* @file install-linux.cpp
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief Linux stub implementations of the driver-loader (install.cpp)
* @details The Windows implementation (install.cpp) loads/unloads the HyperDbg
* kernel-mode driver (the .sys file that contains the actual debugging

View file

@ -18,19 +18,20 @@ extern HANDLE g_SerialListeningThreadHandle;
extern HANDLE g_SerialRemoteComPortHandle;
extern HANDLE g_DebuggeeStopCommandEventHandle;
extern DEBUGGER_SYNCRONIZATION_EVENTS_STATE
g_KernelSyncronizationObjectsHandleTable[DEBUGGER_MAXIMUM_SYNCRONIZATION_KERNEL_DEBUGGER_OBJECTS];
extern BYTE g_CurrentRunningInstruction[MAXIMUM_INSTR_SIZE];
extern BOOLEAN g_IsConnectedToHyperDbgLocally;
g_KernelSyncronizationObjectsHandleTable[DEBUGGER_MAXIMUM_SYNCRONIZATION_KERNEL_DEBUGGER_OBJECTS];
extern BYTE g_CurrentRunningInstruction[MAXIMUM_INSTR_SIZE];
extern BOOLEAN g_IsConnectedToHyperDbgLocally;
#ifdef _WIN32
extern OVERLAPPED g_OverlappedIoStructureForReadDebugger;
extern OVERLAPPED g_OverlappedIoStructureForWriteDebugger;
extern OVERLAPPED g_OverlappedIoStructureForReadDebuggee;
extern OVERLAPPED g_OverlappedIoStructureForReadDebugger;
extern OVERLAPPED g_OverlappedIoStructureForWriteDebugger;
extern OVERLAPPED g_OverlappedIoStructureForReadDebuggee;
#endif // _WIN32
extern DEBUGGER_EVENT_AND_ACTION_RESULT g_DebuggeeResultOfRegisteringEvent;
extern DEBUGGER_EVENT_AND_ACTION_RESULT
g_DebuggeeResultOfAddingActionsToEvent;
extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee;
extern BOOLEAN g_IsSerialConnectedToRemoteDebugger;
extern BOOLEAN g_KdReceiveFromDebuggerDesyncReported;
extern BOOLEAN g_IsDebuggerConntectedToNamedPipe;
extern BOOLEAN g_IsDebuggeeRunning;
extern BOOLEAN g_IsKdModuleLoaded;
@ -335,6 +336,38 @@ KdSendFlushPacketToDebuggee()
return TRUE;
}
/**
* @brief Send a CPUID request to the debuggee
*
* @return BOOLEAN
*/
BOOLEAN
KdSendUserCpuidPacketToDebuggee(UINT32 FunctionId, UINT32 SubFunctionId)
{
DEBUGGER_CPUID_REQUEST_RESPONSE CpuidPacket = {0};
CpuidPacket.FunctionId = FunctionId;
CpuidPacket.SubFunctionId = SubFunctionId;
//
// Send 'ucpuid' command as CPUID packet
//
if (!KdCommandPacketAndBufferToDebuggee(
DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT,
DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_CPUID_REQUEST,
(CHAR *)&CpuidPacket,
sizeof(DEBUGGER_CPUID_REQUEST_RESPONSE)))
{
return FALSE;
}
//
// Wait until the result of CPUID received
//
DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_CPUID_RESULT);
return TRUE;
}
/**
* @brief Send a callstack request to the debuggee
* @param BaseAddress
@ -699,7 +732,7 @@ KdSendRegisterEventPacketToDebuggee(PDEBUGGER_GENERAL_EVENT_DETAIL Event,
EventBufferLength);
PlatformZeroMemory(&g_DebuggeeResultOfRegisteringEvent,
sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT));
sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT));
//
// Send register event packet
@ -766,7 +799,7 @@ KdSendAddActionToEventPacketToDebuggee(PDEBUGGER_GENERAL_ACTION GeneralAction,
GeneralActionLength);
PlatformZeroMemory(&g_DebuggeeResultOfAddingActionsToEvent,
sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT));
sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT));
//
// Send add action to event packet
@ -1558,6 +1591,245 @@ KdGetWindowVersion(CHAR * BufferToSave)
#endif // _WIN32
}
//
// Set when the debugger-side serial receiver desyncs, so the warning is shown
// once per episode (cleared on the next good frame) instead of on every
// overflow while the stream stays desynced.
//
static BOOLEAN g_KdSerialReceiverDesyncReported = FALSE;
/**
* @brief Read a single byte from the debuggee over the serial link
*
* @details Encapsulates the platform-specific single-byte read used by the
* debugger-side receiver so the framing loop and the resync path share one
* implementation.
*
* @param ReadData receives the byte that was read
* @param NoBytesRead receives the number of bytes actually read
*
* @return BOOLEAN TRUE on a successful read, FALSE on a hard read error
*/
static BOOLEAN
KdReadByteFromDebuggeeSerial(CHAR * ReadData, DWORD * NoBytesRead)
{
#ifdef _WIN32
//
// Try to read one byte in overlapped I/O (in debugger)
//
if (!ReadFile(g_SerialRemoteComPortHandle, ReadData, sizeof(CHAR), NULL, &g_OverlappedIoStructureForReadDebugger))
{
DWORD e = GetLastError();
if (e != ERROR_IO_PENDING)
{
return FALSE;
}
}
//
// Wait till one packet becomes available
//
WaitForSingleObject(g_OverlappedIoStructureForReadDebugger.hEvent,
INFINITE);
//
// Get the result
//
GetOverlappedResult(g_SerialRemoteComPortHandle,
&g_OverlappedIoStructureForReadDebugger,
NoBytesRead,
FALSE);
//
// Reset event for next try
//
ResetEvent(g_OverlappedIoStructureForReadDebugger.hEvent);
return TRUE;
#else
//
// Linux: read one byte through the cross-platform serial transport
//
return PlatformSerialReadByte(g_SerialRemoteComPortHandle,
ReadData,
NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGER);
#endif // _WIN32
}
/**
* @brief Read a single byte from the debugger over the serial link
*
* @details Debuggee-side counterpart of KdReadByteFromDebuggeeSerial(); reads
* through the read-from-debugger overlapped structure so the framing loop and
* the resync path share one implementation.
*
* @param ReadData receives the byte that was read
* @param NoBytesRead receives the number of bytes actually read
*
* @return BOOLEAN TRUE on a successful read, FALSE on a hard read error
*/
static BOOLEAN
KdReadByteFromDebuggerSerial(CHAR * ReadData, DWORD * NoBytesRead)
{
#ifdef _WIN32
//
// Try to read one byte in overlapped I/O (in debuggee)
//
if (!ReadFile(g_SerialRemoteComPortHandle, ReadData, sizeof(CHAR), NULL, &g_OverlappedIoStructureForReadDebuggee))
{
DWORD e = GetLastError();
if (e != ERROR_IO_PENDING)
{
return FALSE;
}
}
//
// Wait till one packet becomes available
//
WaitForSingleObject(g_OverlappedIoStructureForReadDebuggee.hEvent,
INFINITE);
//
// Get the result
//
GetOverlappedResult(g_SerialRemoteComPortHandle,
&g_OverlappedIoStructureForReadDebuggee,
NoBytesRead,
FALSE);
//
// Reset event for next try
//
ResetEvent(g_OverlappedIoStructureForReadDebuggee.hEvent);
return TRUE;
#else
//
// Linux: read one byte through the cross-platform serial transport
// (the 5s read timeout is applied inside the platform layer)
//
return PlatformSerialReadByte(g_SerialRemoteComPortHandle,
ReadData,
NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGEE);
#endif // _WIN32
}
/**
* @brief Discard bytes until the next end-of-buffer marker, re-aligning the
* debugger-side serial receiver to a frame boundary after a desync
*
* @details Mirrors SerialConnectionResyncToNextFrame() on the debuggee side
* Bounded by SERIAL_RESYNC_MAX_BYTES so a dead or garbage link cannot spin
* forever
*
* @param IsDebuggee
*
* @return BOOLEAN TRUE if a marker was found (stream re-aligned), FALSE if too
* many bytes arrived without one (treat the link as dead)
*/
BOOLEAN
KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_ENUM ReSyncType)
{
BOOL Status;
BYTE Window[SERIAL_END_OF_BUFFER_CHARS_COUNT] = {NULL_ZERO, NULL_ZERO, NULL_ZERO, NULL_ZERO};
UINT32 Discarded = 0;
while (Discarded < SERIAL_RESYNC_MAX_BYTES)
{
CHAR ReadData = NULL_ZERO;
DWORD NoBytesRead = 0;
if (ReSyncType == DEBUGGER_PACKET_RESYNC_DEBUGGEE)
{
//
// It is for the debuggee
//
if (!KdReadByteFromDebuggeeSerial(&ReadData, &NoBytesRead))
{
return FALSE;
}
}
else if (ReSyncType == DEBUGGER_PACKET_RESYNC_DEBUGGER)
{
//
// It is for the debugger
//
if (!KdReadByteFromDebuggerSerial(&ReadData, &NoBytesRead))
{
return FALSE;
}
}
else if (ReSyncType == DEBUGGER_PACKET_RESYNC_LISTENING)
{
#ifdef _WIN32
Status = ReadFile(g_SerialRemoteComPortHandle, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);
#else
//
// Linux: read one byte through the cross-platform serial transport
//
Status = PlatformSerialReadByte(g_SerialRemoteComPortHandle,
&ReadData,
&NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGEE);
#endif // _WIN32
if (!Status)
{
return FALSE;
}
}
else
{
ShowMessages("err, invalid resync type\n");
return FALSE;
}
if (NoBytesRead == 0)
{
if (ReSyncType == DEBUGGER_PACKET_RESYNC_DEBUGGEE || ReSyncType == DEBUGGER_PACKET_RESYNC_LISTENING)
{
//
// For the debuggee and listening
//
continue;
}
else if (DEBUGGER_PACKET_RESYNC_DEBUGGER)
{
//
// For the debugger
//
//
// The read timed out with no data: the link is idle, so stop
// discarding and let the caller fall back to its idle handling.
//
return FALSE;
}
}
Window[0] = Window[1];
Window[1] = Window[2];
Window[2] = Window[3];
Window[3] = (BYTE)ReadData;
Discarded++;
if (Window[0] == SERIAL_END_OF_BUFFER_CHAR_1 &&
Window[1] == SERIAL_END_OF_BUFFER_CHAR_2 &&
Window[2] == SERIAL_END_OF_BUFFER_CHAR_3 &&
Window[3] == SERIAL_END_OF_BUFFER_CHAR_4)
{
return TRUE;
}
}
return FALSE;
}
/**
* @brief Receive packet from the debuggee
*
@ -1579,54 +1851,10 @@ KdReceivePacketFromDebuggee(CHAR * BufferToSave,
//
do
{
#ifdef _WIN32
//
// It's in the debugger
//
//
// Try to read one byte in overlapped I/O (in debugger)
//
if (!ReadFile(g_SerialRemoteComPortHandle, &ReadData, sizeof(ReadData), NULL, &g_OverlappedIoStructureForReadDebugger))
{
DWORD e = GetLastError();
if (e != ERROR_IO_PENDING)
{
return FALSE;
}
}
//
// Wait till one packet becomes available
//
WaitForSingleObject(g_OverlappedIoStructureForReadDebugger.hEvent,
INFINITE);
//
// Get the result
//
GetOverlappedResult(g_SerialRemoteComPortHandle,
&g_OverlappedIoStructureForReadDebugger,
&NoBytesRead,
FALSE);
//
// Reset event for next try
//
ResetEvent(g_OverlappedIoStructureForReadDebugger.hEvent);
#else
//
// Linux: read one byte through the cross-platform serial transport
//
if (!PlatformSerialReadByte(g_SerialRemoteComPortHandle,
&ReadData,
&NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGER))
if (!KdReadByteFromDebuggeeSerial(&ReadData, &NoBytesRead))
{
return FALSE;
}
#endif
//
// We already now that the maximum packet size is MaxSerialPacketSize
@ -1635,11 +1863,30 @@ KdReceivePacketFromDebuggee(CHAR * BufferToSave,
if (!(MaxSerialPacketSize > Loop))
{
//
// Invalid buffer
// Overflowed without an end-of-buffer marker: the stream is
// desynced (the debuggee most likely dropped the link mid-frame
// without sending a close packet). Returning FALSE here sends the
// caller straight back into the same desynced stream, which
// overflows again at once and floods the output. Show the warning
// once per episode and resync to the next frame boundary instead.
//
ShowMessages("err, a buffer received in which exceeds the "
"buffer limitation\n");
return FALSE;
if (!g_KdSerialReceiverDesyncReported)
{
ShowMessages("err, serial stream desynced (a buffer exceeded the "
"buffer limitation with no end marker); resyncing\n");
g_KdSerialReceiverDesyncReported = TRUE;
}
if (!KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_DEBUGGEE))
{
//
// Too many bytes without a marker: treat the link as dead.
//
return FALSE;
}
Loop = 0;
continue;
}
BufferToSave[Loop] = ReadData;
@ -1653,6 +1900,11 @@ KdReceivePacketFromDebuggee(CHAR * BufferToSave,
} while (NoBytesRead > 0);
//
// A full frame arrived, so the stream is back in sync.
//
g_KdSerialReceiverDesyncReported = FALSE;
//
// Set the length
//
@ -1701,55 +1953,10 @@ KdReceivePacketFromDebugger(CHAR * BufferToSave,
//
do
{
#ifdef _WIN32
//
// It's in the debuggee
//
//
// Try to read one byte in overlapped I/O (in debugger)
//
if (!ReadFile(g_SerialRemoteComPortHandle, &ReadData, sizeof(ReadData), NULL, &g_OverlappedIoStructureForReadDebuggee))
{
DWORD e = GetLastError();
if (e != ERROR_IO_PENDING)
{
return FALSE;
}
}
//
// Wait till one packet becomes available
//
WaitForSingleObject(g_OverlappedIoStructureForReadDebuggee.hEvent,
INFINITE);
//
// Get the result
//
GetOverlappedResult(g_SerialRemoteComPortHandle,
&g_OverlappedIoStructureForReadDebuggee,
&NoBytesRead,
FALSE);
//
// Reset event for next try
//
ResetEvent(g_OverlappedIoStructureForReadDebuggee.hEvent);
#else
//
// Linux: read one byte through the cross-platform serial transport
// (the 5s read timeout is applied inside the platform layer)
//
if (!PlatformSerialReadByte(g_SerialRemoteComPortHandle,
&ReadData,
&NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGEE))
if (!KdReadByteFromDebuggerSerial(&ReadData, &NoBytesRead))
{
return FALSE;
}
#endif
//
// We already now that the maximum packet size is MaxSerialPacketSize
@ -1758,11 +1965,31 @@ KdReceivePacketFromDebugger(CHAR * BufferToSave,
if (!(MaxSerialPacketSize > Loop))
{
//
// Invalid buffer
// Overflowed without an end-of-buffer marker: the stream is
// desynced (the debugger most likely dropped the link mid-frame
// without sending a close packet). Returning FALSE here sends the
// caller straight back into the same desynced stream, which
// overflows again at once and floods the output. Show the warning
// once per episode and resync to the next frame boundary instead.
//
ShowMessages("err, a buffer received in which exceeds the "
"buffer limitation\n");
return FALSE;
if (!g_KdReceiveFromDebuggerDesyncReported)
{
ShowMessages("err, serial stream desynced (a buffer exceeded the "
"buffer limitation with no end marker); resyncing\n");
g_KdReceiveFromDebuggerDesyncReported = TRUE;
}
if (!KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_DEBUGGER))
{
//
// The link went idle or stayed garbage past the bound: treat it
// as dead so the caller can fall back to its idle handling.
//
return FALSE;
}
Loop = 0;
continue;
}
BufferToSave[Loop] = ReadData;
@ -1776,6 +2003,11 @@ KdReceivePacketFromDebugger(CHAR * BufferToSave,
} while (NoBytesRead > 0);
//
// A full frame arrived, so the stream is back in sync.
//
g_KdReceiveFromDebuggerDesyncReported = FALSE;
//
// Set the length
//
@ -2495,7 +2727,7 @@ KdPrepareAndConnectDebugPort(const CHAR * PortName,
BOOLEAN IsNamedPipe,
BOOLEAN PauseAfterConnection)
{
HANDLE Comm; /* Handle to the Serial port */
HANDLE Comm; /* Handle to the Serial port */
#ifdef _WIN32
BOOL Status; /* Status */
DCB SerialParams = {0}; /* Initializing DCB structure */

View file

@ -18,6 +18,7 @@
extern BYTE g_CurrentRunningInstruction[MAXIMUM_INSTR_SIZE];
extern HANDLE g_SerialRemoteComPortHandle;
extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee;
extern BOOLEAN g_ListeningDebuggeeDesyncReported;
extern BOOLEAN g_IsDebuggeeRunning;
extern BOOLEAN g_IgnoreNewLoggingMessages;
extern BOOLEAN g_SharedEventStatus;
@ -56,6 +57,7 @@ ListeningSerialPortInDebugger()
PDEBUGGEE_RESULT_OF_SEARCH_PACKET SearchResultsPacket;
PDEBUGGEE_DETAILS_AND_SWITCH_THREAD_PACKET ChangeThreadPacket;
PDEBUGGER_FLUSH_LOGGING_BUFFERS FlushPacket;
PDEBUGGER_CPUID_REQUEST_RESPONSE CpuidPacket;
PDEBUGGER_CALLSTACK_REQUEST CallstackPacket;
PDEBUGGER_SINGLE_CALLSTACK_FRAME CallstackFramePacket;
PDEBUGGER_DEBUGGER_TEST_QUERY_BUFFER TestQueryPacket;
@ -577,6 +579,29 @@ StartAgain:
break;
case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_CPUID:
CpuidPacket = (DEBUGGER_CPUID_REQUEST_RESPONSE *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET));
if (CpuidPacket->KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL)
{
UINT32 FunctionId = CpuidPacket->FunctionId;
UINT32 SubFunctionId = CpuidPacket->SubFunctionId;
CommandShowUserCpuidMessage(FunctionId, SubFunctionId, CpuidPacket);
}
else
{
ShowErrorMessage(CpuidPacket->KernelStatus);
}
//
// Signal the event relating to receiving result of CPUID
//
DbgReceivedKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_CPUID_RESULT);
break;
case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_CALLSTACK:
CallstackPacket = (DEBUGGER_CALLSTACK_REQUEST *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET));
@ -1442,7 +1467,7 @@ StartAgain:
CHAR SerialBuffer[MaxSerialPacketSize] = {
0}; /* Buffer to send and receive data */
#ifdef _WIN32
DWORD EventMask = 0; /* Event mask to trigger */
DWORD EventMask = 0; /* Event mask to trigger */
#endif // _WIN32
char ReadData = NULL; /* temperory Character */
DWORD NoBytesRead = 0; /* Bytes read by ReadFile() */
@ -1503,23 +1528,50 @@ StartAgain:
PLATFORM_SERIAL_IO_DEBUGGEE);
#endif // _WIN32
//
// Hard read error: restart the listen. StartAgain re-arms the wait,
// which blocks until data arrives, so it cannot busy-loop.
//
if (!Status)
{
goto StartAgain;
}
//
// Check to make sure that we don't pass the boundaries
//
if (!Status || !(MaxSerialPacketSize > Loop))
if (!(MaxSerialPacketSize > Loop))
{
//
// Invalid buffer
// Overflowed without an end-of-buffer marker: the stream is
// desynced. Restarting into the same desynced stream floods the
// output, so show the warning once per episode and resync to the
// next frame boundary instead.
//
ShowMessages("err, a buffer received in debuggee which exceeds the "
"buffer limitation\n");
goto StartAgain;
if (!g_ListeningDebuggeeDesyncReported)
{
ShowMessages("err, serial stream desynced in debuggee (a buffer "
"exceeded the buffer limitation with no end marker); resyncing\n");
g_ListeningDebuggeeDesyncReported = TRUE;
}
if (!KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_LISTENING))
{
goto StartAgain;
}
Loop = 0;
continue;
}
SerialBuffer[Loop] = ReadData;
if (KdCheckForTheEndOfTheBuffer(&Loop, (BYTE *)SerialBuffer))
{
//
// A full frame arrived, so the stream is back in sync.
//
g_ListeningDebuggeeDesyncReported = FALSE;
break;
}

View file

@ -118,6 +118,7 @@ AssembleData::ParseAssemblyData()
INT
AssembleData::Assemble(UINT64 StartAddr, ks_arch Arch, INT Mode, INT Syntax)
{
#ifdef _WIN32
ks_engine * Ks;
KsErr = ks_open(Arch, Mode, &Ks);
@ -175,6 +176,24 @@ AssembleData::Assemble(UINT64 StartAddr, ks_arch Arch, INT Mode, INT Syntax)
}
ks_close(Ks);
return -1;
#else
//
// TODO(Linux): the Keystone assembler engine is not linked on Linux. Only a
// Windows keystone.lib is vendored (libraries/keystone/release-lib) and
// dependencies/keystone/ ships headers only, so the ks_* types and constants
// resolve but the 5 ks_* functions do not. Build upstream Keystone for Linux
// and restore link_directories()/target_link_libraries(keystone) in the
// top-level CMakeLists.txt to make this real.
//
UNREFERENCED_PARAMETER(StartAddr);
UNREFERENCED_PARAMETER(Arch);
UNREFERENCED_PARAMETER(Mode);
UNREFERENCED_PARAMETER(Syntax);
ShowMessages("err, the assembler is not supported on Linux yet\n");
return -1;
#endif
}
AssembleData *

View file

@ -73,7 +73,18 @@ ReadLine(CHAR * DestBuffer, UINT64 CharLimit, CHAR ** SrcBuffer)
}
else
{
strncpy_s(DestBuffer, CharLimit, *SrcBuffer, (Line - *SrcBuffer));
//
// The copy length is clamped to the destination, otherwise a line longer than
// CharLimit makes strncpy_s() invoke the invalid parameter handler
//
SIZE_T LineLength = (SIZE_T)(Line - *SrcBuffer);
if (LineLength > CharLimit - 1)
{
LineLength = (SIZE_T)(CharLimit - 1);
}
PlatformStrNCpy(DestBuffer, (SIZE_T)CharLimit, *SrcBuffer, LineLength);
*SrcBuffer += (Line - *SrcBuffer + 1);
return *SrcBuffer;
}
@ -103,22 +114,40 @@ GetVendorByIdStr(const CHAR * Filename, const CHAR * VendorId)
if (f == NULL)
{
ShowMessages("Error: Cannot open file '%s': error %d\n", Filename, errno);
ShowMessages("err, cannot open file '%s' (error 0x%x)\n", Filename, errno);
return NULL;
}
fseek(f, 0, SEEK_END);
Length = ftell(f);
PciIdDatabaseBuffer = (CHAR *)malloc(Length);
LONG FileSize = ftell(f);
if (FileSize < 0)
{
ShowMessages("err, cannot determine the size of file '%s' (error: 0x%x)\n", Filename, errno);
fclose(f);
return NULL;
}
Length = (SIZE_T)FileSize;
//
// One extra byte is allocated for the null terminator, as the buffer is later
// walked with strchr() by ReadLine() and would otherwise be read past its end
//
PciIdDatabaseBuffer = (CHAR *)malloc(Length + 1);
if (!PciIdDatabaseBuffer)
{
fclose(f);
return NULL;
}
fseek(f, 0, SEEK_SET);
fread(PciIdDatabaseBuffer, 1, Length, f);
SIZE_T BytesRead = fread(PciIdDatabaseBuffer, 1, Length, f);
fclose(f);
PciIdDatabaseBuffer[BytesRead] = '\0';
}
PciIdDbBufPtr = PciIdDatabaseBuffer;
@ -142,9 +171,19 @@ GetVendorByIdStr(const CHAR * Filename, const CHAR * VendorId)
snprintf(FormatStr, sizeof(FormatStr), "%%4s %%%d[^\n]", PCI_NAME_STR_LENGTH); // FormatStr = "%4s %PCI_NAME_STR_LENGTH[^\n]"
if (sscanf(Line, FormatStr, VendorBuf, VendorNameBuf) == 2)
{
if (strncmp(VendorBuf, VendorId, sizeof(VendorId)) == 0)
//
// VendorId is a pointer, so sizeof() on it yielded the pointer size
// rather than the length of a PCI vendor id
//
if (strncmp(VendorBuf, VendorId, PCI_ID_AS_STR_LENGTH) == 0)
{
MatchedVendor = (Vendor *)malloc(sizeof(Vendor));
//
// calloc() so that the Devices list head starts out empty: it is
// only assigned once a device line is parsed, and FreeVendor()
// would otherwise walk an uninitialized pointer for a vendor that
// has no devices listed
//
MatchedVendor = (Vendor *)calloc(1, sizeof(Vendor));
if (!MatchedVendor)
{
return NULL;
@ -153,9 +192,10 @@ GetVendorByIdStr(const CHAR * Filename, const CHAR * VendorId)
INT Result = sscanf(VendorBuf, "%hx", &(MatchedVendor->VendorId));
if (Result != 1)
{
FreeVendor(MatchedVendor);
return NULL;
}
strncpy_s(MatchedVendor->VendorName, sizeof(MatchedVendor->VendorName), TrimWhitespace(VendorNameBuf, PCI_NAME_STR_LENGTH), _TRUNCATE);
PlatformStrNCpy(MatchedVendor->VendorName, sizeof(MatchedVendor->VendorName), TrimWhitespace(VendorNameBuf, PCI_NAME_STR_LENGTH), _TRUNCATE);
FoundVendorId = TRUE;
}
}
@ -178,11 +218,16 @@ GetVendorByIdStr(const CHAR * Filename, const CHAR * VendorId)
int Result = sscanf(DeviceBuf, "%hx", &(NewDevice->DeviceId));
if (Result != 1)
{
//
// NewDevice is not linked into the vendor's list yet, so it has to
// be released separately from FreeVendor()
//
free(NewDevice);
FreeVendor(MatchedVendor);
return NULL;
}
strncpy_s(NewDevice->DeviceName, sizeof(NewDevice->DeviceName), TrimWhitespace(DeviceNameBuf, PCI_NAME_STR_LENGTH), _TRUNCATE);
PlatformStrNCpy(NewDevice->DeviceName, sizeof(NewDevice->DeviceName), TrimWhitespace(DeviceNameBuf, PCI_NAME_STR_LENGTH), _TRUNCATE);
NewDevice->SubDevices = NULL;
NewDevice->Next = NULL;
@ -216,6 +261,11 @@ GetVendorByIdStr(const CHAR * Filename, const CHAR * VendorId)
int Result = sscanf(SubVendorBuf, "%hx", &NewSubDevice->SubVendorId);
if (Result != 1)
{
//
// NewSubDevice is not linked into the device's list yet, so it has
// to be released separately from FreeVendor()
//
free(NewSubDevice);
FreeVendor(MatchedVendor);
return NULL;
}
@ -223,11 +273,12 @@ GetVendorByIdStr(const CHAR * Filename, const CHAR * VendorId)
Result = sscanf(SubDeviceBuf, "%hx", &NewSubDevice->SubDeviceId);
if (Result != 1)
{
free(NewSubDevice);
FreeVendor(MatchedVendor);
return NULL;
}
strncpy_s(NewSubDevice->SubSystemName, sizeof(NewSubDevice->SubSystemName), TrimWhitespace(SubsystemNameBuf, PCI_NAME_STR_LENGTH), _TRUNCATE);
PlatformStrNCpy(NewSubDevice->SubSystemName, sizeof(NewSubDevice->SubSystemName), TrimWhitespace(SubsystemNameBuf, PCI_NAME_STR_LENGTH), _TRUNCATE);
NewSubDevice->Next = NULL;
if (LastSubDevice)
@ -278,6 +329,13 @@ FreeVendor(Vendor * VendorToFree)
free(CurrentDevice);
CurrentDevice = NextDevice;
}
//
// The Vendor itself is allocated by GetVendorByIdStr() and was previously never
// released, leaking one Vendor per call for every PCI device that got enumerated
//
VendorToFree->Devices = NULL;
free(VendorToFree);
}
/**
@ -304,12 +362,23 @@ FreePciIdDatabase()
Vendor *
GetVendorById(UINT16 VendorId)
{
#ifdef _WIN32
CHAR VendorIdAsStr[5];
CHAR ExecutablePath[MAX_PATH];
HMODULE hModule = GetModuleHandle(NULL);
snprintf(VendorIdAsStr, sizeof(VendorIdAsStr), "%04X", VendorId);
GetModuleFileName(hModule, ExecutablePath, sizeof(ExecutablePath));
DWORD PathLength = GetModuleFileName(hModule, ExecutablePath, sizeof(ExecutablePath));
//
// A zero length means the call failed; a length equal to the buffer size means the
// path was truncated and, on older Windows versions, left without a null terminator
//
if (PathLength == 0 || PathLength >= sizeof(ExecutablePath))
{
return NULL;
}
// Extract executable name
CHAR * ExecutableName = strrchr(ExecutablePath, '\\');
@ -323,9 +392,31 @@ GetVendorById(UINT16 VendorId)
}
// Swap executable name for PCI_ID_DATABASE_PATH
strncpy(ExecutableName, PCI_ID_DATABASE_PATH, sizeof(PCI_ID_DATABASE_PATH));
//
// The database path can be longer than the executable name it replaces, so the
// room left in ExecutablePath is checked before overwriting the tail
//
SIZE_T RemainingSpace = sizeof(ExecutablePath) - (SIZE_T)(ExecutableName - ExecutablePath);
if (RemainingSpace < sizeof(PCI_ID_DATABASE_PATH))
{
return NULL;
}
memcpy(ExecutableName, PCI_ID_DATABASE_PATH, sizeof(PCI_ID_DATABASE_PATH));
return GetVendorByIdStr(ExecutablePath, ToLower(VendorIdAsStr));
#else
//
// TODO(Linux): resolve the PCI ID database next to the executable via
// readlink("/proc/self/exe") once the path separator and
// PCI_ID_DATABASE_PATH ("constants\\pci.ids") are made portable. Until
// then no vendor/device names are available on Linux.
//
UNREFERENCED_PARAMETER(VendorId);
return NULL;
#endif
}
/**

View file

@ -346,6 +346,7 @@ ScriptEngineEvalWrapper(PGUEST_REGS GuestRegs,
string Expr)
{
SCRIPT_ENGINE_GENERAL_REGISTERS ScriptGeneralRegisters = {0};
g_CurrentExprEvalResultHasError = FALSE;
//
// Allocate global variables holder
@ -477,6 +478,7 @@ ScriptEngineEvalWrapper(PGUEST_REGS GuestRegs,
else
{
ShowMessages("%s\n", CodeBuffer->Message);
g_CurrentExprEvalResultHasError = TRUE;
}
RemoveSymbolBuffer(CodeBuffer);

View file

@ -1,6 +1,6 @@
/**
* @file symbol-linux.cpp
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief Linux stub implementations of the symbol subsystem
* @details The Windows implementation uses DbgHelp + PDB files (symbol-parser/).
* Linux uses ELF/DWARF which requires a separate implementation.

View file

@ -22,6 +22,7 @@ extern TCHAR g_TestLocation[MAX_PATH];
* @param BufferLength Setup test process name
* @return BOOLEAN
*/
#ifdef _WIN32
BOOLEAN
SetupTestName(_Inout_updates_bytes_all_(BufferLength) PCHAR TestLocation,
ULONG BufferLength)
@ -98,6 +99,7 @@ SetupTestName(_Inout_updates_bytes_all_(BufferLength) PCHAR TestLocation,
//
return TRUE;
}
#endif // _WIN32
/**
* @brief Create a Process And Open Pipe Connection object
@ -112,6 +114,7 @@ CreateProcessAndOpenPipeConnection(PHANDLE ConnectionPipeHandle,
PHANDLE ThreadHandle,
PHANDLE ProcessHandle)
{
#ifdef _WIN32
HANDLE PipeHandle;
BOOLEAN SentMessageResult;
UINT32 ReadBytes;
@ -297,6 +300,18 @@ CreateProcessAndOpenPipeConnection(PHANDLE ConnectionPipeHandle,
free(BufferToSend);
return FALSE;
#else
//
// TODO(Linux): the test harness spawns a Windows test executable
// (hyperdbg-test.exe) and handshakes with it over a named pipe. There is no
// Linux backend yet — both the process spawn (CreateProcess / STARTUPINFO)
// and the named pipe are stubbed — so this returns failure for now.
//
UNREFERENCED_PARAMETER(ConnectionPipeHandle);
UNREFERENCED_PARAMETER(ThreadHandle);
UNREFERENCED_PARAMETER(ProcessHandle);
return FALSE;
#endif // _WIN32
}
/**
@ -313,6 +328,7 @@ OpenHyperDbgTestProcess(PHANDLE ThreadHandle,
PHANDLE ProcessHandle,
CHAR * Args)
{
#ifdef _WIN32
PROCESS_INFORMATION ProcessInfo = {0};
STARTUPINFO StartupInfo = {0};
CHAR CmdArgs[MAX_PATH] = {0};
@ -354,6 +370,16 @@ OpenHyperDbgTestProcess(PHANDLE ThreadHandle,
}
return FALSE;
#else
//
// TODO(Linux): no Linux process-spawn backend yet (the future home is a
// narrow variant of PlatformCreateProcess). STARTUPINFO is Windows-only.
//
UNREFERENCED_PARAMETER(ThreadHandle);
UNREFERENCED_PARAMETER(ProcessHandle);
UNREFERENCED_PARAMETER(Args);
return FALSE;
#endif // _WIN32
}
/**
@ -369,10 +395,20 @@ CloseProcessAndClosePipeConnection(HANDLE ConnectionPipeHandle,
HANDLE ThreadHandle,
HANDLE ProcessHandle)
{
#ifdef _WIN32
//
// Close the connection and handles
//
NamedPipeServerCloseHandle(ConnectionPipeHandle);
CloseHandle(ThreadHandle);
CloseHandle(ProcessHandle);
#else
//
// TODO(Linux): counterpart of the stubbed test-process spawn above; the
// handles are never created on Linux, so there is nothing to close yet.
//
UNREFERENCED_PARAMETER(ConnectionPipeHandle);
UNREFERENCED_PARAMETER(ThreadHandle);
UNREFERENCED_PARAMETER(ProcessHandle);
#endif // _WIN32
}

View file

@ -12,6 +12,13 @@
*/
#include "pch.h"
//
// std::sqrt / pow / log / sqrt: MSVC exposes these transitively through its
// CRT/pch, libstdc++ needs the explicit <cmath> (which also declares the
// unqualified ::pow/::log/::sqrt used below). Standard header, cross-platform-safe.
//
#include <cmath>
/**
* @brief get the median of a vector
*

View file

@ -1,6 +1,6 @@
/**
* @file pe-parser-linux.cpp
* @author Max Raulea (max.raulea@gmail.com)
* @author Max Raulea (max.raulea@hyperdbg.org)
* @brief Linux stub implementations of the PE (Portable Executable) parser
* @details The Windows implementation (pe-parser.cpp) parses the full PE image
* format and depends on the complete set of Windows IMAGE_* headers,

View file

@ -290,6 +290,26 @@ hyperdbg_u_unset_text_message_callback()
UnsetTextMessageCallback();
}
/**
* @brief Execute a script with the deterministic local evaluator used by tests.
*
* @param expression Script body without the leading '?' command token
* @return BOOLEAN TRUE when parsing and evaluation complete without error
*/
BOOLEAN
hyperdbg_u_test_script_engine(CHAR * expression)
{
extern BOOLEAN g_CurrentExprEvalResultHasError;
if (!expression)
{
return FALSE;
}
ScriptEngineWrapperTestParser(expression);
return !g_CurrentExprEvalResultHasError;
}
/**
* @brief Parsing the command line options for scripts
* @param argc
@ -1005,3 +1025,23 @@ hyperdbg_u_pt_mmap(HYPERTRACE_PT_MMAP_PACKETS * MmapRequest)
{
return HyperDbgPtMmapSendRequest(MmapRequest);
}
/**
* @brief Get CPUID information from the target system
*
* @param FunctionId The CPUID leaf (EAX value)
* @param SubFunctionId The CPUID sub-leaf (ECX value)
*
* @return BOOLEAN TRUE if successful, FALSE otherwise
*/
BOOLEAN
hyperdbg_u_request_cpuid(UINT32 FunctionId, UINT32 SubFunctionId)
{
//
// Call the existing CPUID command handler
// This handles both local and remote modes automatically
//
CommandCpuidRequestCpuid(FunctionId, SubFunctionId);
return TRUE;
}

View file

@ -412,7 +412,7 @@ HwdbgScriptSendScriptPacket(HWDBG_INSTANCE_INFORMATION * InstanceInfo,
return FALSE;
}
RtlZeroMemory(FinalBuffer, BufferLength + sizeof(HWDBG_SCRIPT_BUFFER));
PlatformZeroMemory(FinalBuffer, BufferLength + sizeof(HWDBG_SCRIPT_BUFFER));
//
// Copy the packet into the FinalBuffer

View file

@ -301,6 +301,9 @@ typedef std::map<std::string, COMMAND_DETAIL> CommandType;
#define DEBUGGER_COMMAND_FLUSH_ATTRIBUTES \
DEBUGGER_COMMAND_ATTRIBUTE_LOCAL_COMMAND_IN_DEBUGGER_MODE
#define DEBUGGER_COMMAND_USER_CPUID_ATTRIBUTES \
DEBUGGER_COMMAND_ATTRIBUTE_LOCAL_COMMAND_IN_DEBUGGER_MODE
#define DEBUGGER_COMMAND_UNLOAD_ATTRIBUTES NULL
#define DEBUGGER_COMMAND_SCRIPT_ATTRIBUTES \
@ -644,6 +647,9 @@ CommandSettings(vector<CommandToken> CommandTokens, string Command);
VOID
CommandFlush(vector<CommandToken> CommandTokens, string Command);
VOID
CommandUserCpuid(vector<CommandToken> CommandTokens, string Command);
VOID
CommandPause(vector<CommandToken> CommandTokens, string Command);

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