mirror of
https://github.com/HyperDbg/HyperDbg
synced 2026-08-15 06:29:09 -04:00
commit
fa816b4062
131 changed files with 11814 additions and 2093 deletions
40
CHANGELOG.md
40
CHANGELOG.md
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
231
hyperdbg/Kbuild
Normal 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.
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
271
hyperdbg/hyperdbg-test/code/tests/test-script-floating-point.cpp
Normal file
271
hyperdbg/hyperdbg-test/code/tests/test-script-floating-point.cpp
Normal 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;
|
||||
}
|
||||
163
hyperdbg/hyperdbg-test/code/tests/test-script-variable-types.cpp
Normal file
163
hyperdbg/hyperdbg-test/code/tests/test-script-variable-types.cpp
Normal 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; }");
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,3 +26,9 @@ TestCodeViewRsdsParser();
|
|||
|
||||
BOOLEAN
|
||||
TestSemanticScripts();
|
||||
|
||||
BOOLEAN
|
||||
TestScriptEngineFloatingPoint();
|
||||
|
||||
BOOLEAN
|
||||
TestScriptEngineVariableTypes();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -101,3 +101,6 @@ CommonKillProcess(UINT32 ProcessId, PROCESS_KILL_METHODS KillingMethod);
|
|||
|
||||
BOOLEAN
|
||||
CommonValidateCoreNumber(UINT32 CoreNumber);
|
||||
|
||||
VOID
|
||||
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, INT * CpuInfo);
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 //
|
||||
//////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
// ==============================================================================================
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#if defined(__linux__)
|
||||
# include "../../../../include/SDK/HyperDbgSdk.h"
|
||||
# include <linux/cpumask.h>
|
||||
#endif // defined(__linux__)
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
83
hyperdbg/include/platform/user/code/platform-socket.c
Normal file
83
hyperdbg/include/platform/user/code/platform-socket.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
78
hyperdbg/include/platform/user/header/platform-socket.h
Normal file
78
hyperdbg/include/platform/user/header/platform-socket.h
Normal 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);
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
44
hyperdbg/libhyperdbg/code/assembly/asm-vmx-checks-gas-unix.s
Normal file
44
hyperdbg/libhyperdbg/code/assembly/asm-vmx-checks-gas-unix.s
Normal 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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ CommandSym(vector<CommandToken> CommandTokens, string Command)
|
|||
}
|
||||
else
|
||||
{
|
||||
UserProcessId = GetCurrentProcessId();
|
||||
UserProcessId = PlatformGetCurrentProcessId();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue