This commit is contained in:
olari
2021-06-05 21:10:25 +03:00
parent 807cffd9de
commit e0e0f2be99
923 changed files with 911857 additions and 15 deletions

View File

@@ -93,17 +93,17 @@ bool idaapi run( size_t /*arg*/ )
return true;
}
int idaapi init( void )
plugmod_t* idaapi init( void )
{
Settings.Init( );
Settings.Load( "sigmaker.ini" );
return PLUGIN_OK;
return PLUGIN_KEEP;
}
plugin_t PLUGIN = {
IDP_INTERFACE_VERSION,
PLUGIN_KEEP,
0,// PLUGIN_KEEP,
init,
NULL,
run,

View File

@@ -22,34 +22,34 @@
<ProjectGuid>{60916877-60AB-4565-93BC-2D6097976D86}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>SigMaker</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug64|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release64|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -90,7 +90,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SIGMAKER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IDADIR)\idasdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
@@ -114,7 +114,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;__EA64__;SIGMAKER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IDADIR)\idasdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
@@ -139,7 +139,7 @@
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<AdditionalIncludeDirectories>$(IDADIR)\idasdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<IntrinsicFunctions>true</IntrinsicFunctions>
<OpenMPSupport>false</OpenMPSupport>
</ClCompile>
@@ -179,7 +179,7 @@
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<OpenMPSupport>false</OpenMPSupport>
<AdditionalIncludeDirectories>$(IDADIR)\idasdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
@@ -191,16 +191,18 @@
<AdditionalOptions>/EXPORT:PLUGIN %(AdditionalOptions)</AdditionalOptions>
<DataExecutionPrevention>false</DataExecutionPrevention>
<EnableUAC>false</EnableUAC>
<AdditionalLibraryDirectories>$(IDADIR)\idasdk\lib\x64_win_vc_64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(SolutionDir)idasdk75\lib\x64_win_vc_64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<ProjectReference>
<LinkLibraryDependencies>false</LinkLibraryDependencies>
</ProjectReference>
<PostBuildEvent>
<Command>copy "$(TargetDir)$(TargetName)$(TargetExt)" "$(IDADIR)\plugins\sigmaker64.dll"</Command>
<Command>
</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>copy "$(TargetDir)$(TargetName)$(TargetExt)" "$(IDADIR)\plugins\sigmaker64.dll"</Message>
<Message>
</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>

823
idasdk75/allmake.mak Normal file
View File

@@ -0,0 +1,823 @@
#
# Common part of make files for IDA.
#
# find directory of allmake.mak:
IDA:=$(dir $(lastword $(MAKEFILE_LIST)))
# define the version number we are building
IDAVER_MAJOR:=7
IDAVER_MINOR:=5
# 750
IDAVERDECIMAL:=$(IDAVER_MAJOR)$(IDAVER_MINOR)0
# 7.5
IDAVERDOTTED:=$(IDAVER_MAJOR).$(IDAVER_MINOR)
# only 32-bit cygwin make is support on Windows
ifeq ($(OS),Windows_NT)
ifneq ($(MAKE_HOST),i686-pc-cygwin)
$(error Only 32-bit cygwin make is supported on Windows. Make sure you are not using 64-bit cygwin, msys, msys2, or any other version of win32 make)
endif
endif
# if no targets are defined, default to host OS
ifeq ($(or $(__ANDROID__),$(__ANDROID_X86__),$(__ARMLINUX__),$(__LINUX__),$(__MAC__),$(__NT__)),)
ifeq ($(OS),Windows_NT)
__NT__=1
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
__LINUX__=1
endif
ifeq ($(UNAME_S),Darwin)
__MAC__=1
endif
endif
endif
# only one build target may be defined
ifneq ($(__ANDROID__)$(__ANDROID_X86__)$(__ARMLINUX__)$(__LINUX__)$(__MAC__)$(__NT__),1)
$(error Only one build target may be defined (__ANDROID__, __ANDROID_X86__, __ARMLINUX__, __LINUX__, __MAC__, or __NT__))
endif
# detect build configuration
# Note: will set one of M, MM, MMH, M32, MO, MMO, MMHO, MO32, MSO, MMSO, or MSO32
BUILD_CONFIG-1 := M
BUILD_CONFIG-$(__EA64__) += M
BUILD_CONFIG-$(USE_STATIC_RUNTIME) += S
BUILD_CONFIG-$(IDAHOME) += H
BUILD_CONFIG-$(NDEBUG) += O
BUILD_CONFIG-$(__X86__) += 32
empty :=
space := $(empty) $(empty)
comma := ,
BUILD_CONFIG := $(subst $(space),,$(BUILD_CONFIG-1))
$(BUILD_CONFIG) := 1
# definition of a single \n character (empty lines are important!)
define newline
endef
# disable x86 ida64 builds
ifeq ($(or $(MM32),$(MMO32),$(MMSO32)),1)
$(error x86 ida64 builds have been disabled)
endif
ifdef __ARM__
PROCDEF = __ARM__
TARGET_PROCESSOR_NAME=arm
else ifndef __X86__
ARCH_FLAGS = -m64
TARGET_PROCESSOR_NAME=x64
else
ARCH_FLAGS = -m32
TARGET_PROCESSOR_NAME=x86
endif
# define some variables to simplify build system
ifndef __X86__
__X64__ = 1
ifndef __EA64__
__X32__ = 1
endif
endif
ifndef __NT__
__UNIX__ = 1
endif
ifndef IDAHOME
IDAADV = 1
endif
# define SYSNAME
SYSNAME-$(__LINUX__) = linux
SYSNAME-$(__MAC__) = mac
SYSNAME-$(__NT__) = win
SYSNAME = $(SYSNAME-1)
# path functions (depending on host OS)
ifeq ($(OS),Windows_NT)
# define: convert unix path to dos path by replacing slashes by backslashes
dospath=$(subst /,\\,$(1))
else
# define: dospath does not do anything in unix
dospath=$(1)
endif
# define: return 1 if path exists, 0 otherwise
ls=$(if $(wildcard $(1)),1,0)
# define: logical negation
not = $(if $(1),,1)
# define: greater or equal
gte = $(if $(filter-out $(1),$(word 2,$(sort $(1) $(2)))),,1)
include $(IDA)defaults.mk
#############################################################################
ifdef __NT__
COMPILER_NAME=vc
# Visual C++ Toolchain and Windows SDK paths
# Note: see comments in defaults.mk for more information about these
# variables.
# This function searches for a specified path, converts it to a 8.3
# path with forward slashes as separator, and exports it as an
# environment variable. This way, subcalls to make do not need to
# call $(shell) again.
define require_path
$$(if $(strip $$($(1))),,$$(eval $(1):=$$(subst \,/,$$(shell cygpath -d $(2) 2>/dev/null))))
$$(if $(strip $$($(1))),,$$(error Could not find $(3) in $(2)$$(newline)*** See defaults.mk and "Visual C++ Toolchain and Windows SDK paths" in allmake.mak))
$$(eval export $(1))
endef
# This function fixes variables imported from defaults.mk/vcvars.bat
# by ensuring that they are surrounded by quotes and by removing the
# trailing backslash.
fix_var=$(1):='$$(patsubst %\,%,$$(patsubst '%,%,$$(patsubst %',%,$$(patsubst "%,%,$$(patsubst %",%,$$($(1)))))))'
# Note: these cfg files are created in makeenv_vc.mak
ifdef __XPCOMPAT__
-include $(IDA)vs17paths_xp.cfg
else
-include $(IDA)vs17paths.cfg
endif
# Visual C++ 2017 Install Directory
ifndef MSVC_ROOT
ifneq (,$(findstring Microsoft$(space)Visual$(space)Studio$(space),$(VCINSTALLDIR)))
ifeq (,$(findstring 2017,$(VCINSTALLDIR)))
$(error Please check your system environment variable VCInstallDir [$(VCINSTALLDIR)].$(newline)It seems to be pointing to an old version of Visual Studio (and not version 2017).$(newline)You may override it in defaults.mk.)
endif
endif
$(eval $(call fix_var,VCINSTALLDIR))
$(eval $(call require_path,MSVC_ROOT,$(VCINSTALLDIR),Visual C++ 2017 Install Directory))
export MSVC_ROOT
endif
# Visual C++ 2017 Tools Version
ifndef MSVC_TOOLSVER
ifndef VCToolsVersion
# Try to obtain version from Microsoft.VCToolsVersion.default.txt
MSVC_TOOLSVER_PATH = $(MSVC_ROOT)/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt
VCToolsVersion := $(shell cat $(MSVC_TOOLSVER_PATH) 2> /dev/null)
ifeq (,$(VCToolsVersion))
# If that failed, try to detect latest version from the directory names
VCToolsVersion := $(notdir $(lastword $(sort $(wildcard $(MSVC_ROOT)/Tools/MSVC/14.*))))
endif
ifeq (,$(VCToolsVersion))
$(error Could not find Visual C++ 2017 Tools Version in $(MSVC_TOOLSVER_PATH))
endif
endif
$(eval $(call fix_var,VCToolsVersion))
MSVC_TOOLSVER := $(VCToolsVersion)
export MSVC_TOOLSVER
endif
# Final Visual C++ 2017 Tools path
$(eval $(call require_path,MSVC_PATH,$(MSVC_ROOT)/Tools/MSVC/$(MSVC_TOOLSVER),Visual C++ 2017 Tools))
MSVC_BIN-X86 ?= $(MSVC_PATH)/bin/HostX86/x86
MSVC_BIN-X64 ?= $(MSVC_PATH)/bin/HostX64/x64
ifdef __X86__
MSVC_BIN ?= $(MSVC_BIN-X86)
else
MSVC_BIN ?= $(MSVC_BIN-X64)
endif
MSVC_INCLUDE ?= $(MSVC_PATH)/Include
# Windows SDK Install Directory
ifndef WSDK_PATH
$(eval $(call fix_var,WindowsSdkDir))
$(eval $(call require_path,WSDK_PATH,$(WindowsSdkDir),Windows SDK Install Directory))
export WSDK_PATH
endif
# Windows SDK Version
ifndef WSDK_VER
ifndef WindowsSDKVersion
# Detect the latest version of the Windows SDK
WSDK_VER_PATH = $(WSDK_PATH)/Include/10.*
WindowsSDKVersion := $(notdir $(lastword $(sort $(wildcard $(WSDK_VER_PATH)))))
ifeq (,$(WindowsSDKVersion))
$(error Could not find Windows SDK Version in $(WSDK_VER_PATH))
endif
endif
$(eval $(call fix_var,WindowsSDKVersion))
WSDK_VER := $(WindowsSDKVersion)
export WSDK_VER
endif
# Windows SDK Include/Lib paths
INCLUDE_UCRT_PATH ?= $(WSDK_PATH)/Include/$(WSDK_VER)/ucrt
LIB_UCRT_PATH ?= $(WSDK_PATH)/Lib/$(WSDK_VER)/ucrt
$(eval $(call require_path,INCLUDE_UCRT,$(INCLUDE_UCRT_PATH),Windows SDK Include/ucrt))
$(eval $(call require_path,LIB_UCRT,$(LIB_UCRT_PATH),Windows SDK Lib/ucrt))
ifdef __XPCOMPAT__
$(eval $(call require_path,INCLUDE_MSSDK71,$(MSSDK71_PATH)/Include,Microsoft SDK Include))
$(eval $(call require_path,LIB_MSSDK71,$(MSSDK71_PATH)/Lib,Microsoft SDK Lib))
$(eval $(call require_path,SDK_BIN,$(MSSDK71_PATH)/Bin,Microsoft SDK Bin))
else
INCLUDE_SHARED_PATH ?= $(WSDK_PATH)/Include/$(WSDK_VER)/shared
INCLUDE_UM_PATH ?= $(WSDK_PATH)/Include/$(WSDK_VER)/um
LIB_UM_PATH ?= $(WSDK_PATH)/Lib/$(WSDK_VER)/um
SDK_BIN_PATH ?= $(WSDK_PATH)/Bin/$(WSDK_VER)/
$(eval $(call require_path,INCLUDE_SHARED,$(INCLUDE_SHARED_PATH),Windows SDK Include/shared))
$(eval $(call require_path,INCLUDE_UM,$(INCLUDE_UM_PATH),Windows SDK Include/um))
$(eval $(call require_path,LIB_UM,$(LIB_UM_PATH),Windows SDK Lib/um))
$(eval $(call require_path,SDK_BIN,$(SDK_BIN_PATH),Windows SDK Bin))
endif
# Export INCLUDE as an environment variable so it may be used by cl.
ifndef INCLUDE
ifdef __XPCOMPAT__
INCLUDE = $(MSVC_INCLUDE);$(INCLUDE_UCRT);$(INCLUDE_MSSDK71)
else
INCLUDE = $(MSVC_INCLUDE);$(INCLUDE_UCRT);$(INCLUDE_UM);$(INCLUDE_SHARED)
endif
export INCLUDE
endif
# Export LIB as an environment variable so it may be used by cl/link.
ifndef LIB
ifdef __XPCOMPAT__
ifdef __X86__
LIB = $(MSVC_PATH)/lib/x86;$(LIB_UCRT)/x86;$(LIB_MSSDK71)
else
LIB = $(MSVC_PATH)/lib/x64;$(LIB_UCRT)/x64;$(LIB_MSSDK71)/x64
endif
else
ifdef __X86__
LIB = $(MSVC_PATH)/lib/x86;$(LIB_UCRT)/x86;$(LIB_UM)/x86
else
LIB = $(MSVC_PATH)/lib/x64;$(LIB_UCRT)/x64;$(LIB_UM)/x64
endif
endif
export LIB
endif
# If a Visual Studio Command Prompt is used, make sure the target
# architecture is correct.
ifdef VSCMD_ARG_TGT_ARCH
ifneq ($(VSCMD_ARG_TGT_ARCH),$(TARGET_PROCESSOR_NAME))
ifdef __X86__
EXPECTED_ARCH = x86
else
EXPECTED_ARCH = x64
endif
LOWERCASE_BUILD_CONFIG := $(subst M,m,$(subst S,s,$(subst O,o,$(BUILD_CONFIG))))
$(error Please use the correct Visual Studio Command Prompt for the target architecture$(newline)*** The target architecture for '$(LOWERCASE_BUILD_CONFIG)' is $(EXPECTED_ARCH), and the architecture for the current Visual Studio Command Prompt is $(VSCMD_ARG_TGT_ARCH)))
endif
endif
#############################################################################
else ifdef __LINUX__
COMPILER_NAME=gcc
PTHR_SWITCH=-pthread
STDLIBS += -lrt -lpthread -lc
#############################################################################
else ifdef __MAC__
COMPILER_NAME=clang
STDLIBS += -lpthread -liconv
ARCH_FLAGS-$(__X64__) = -arch x86_64
ARCH_FLAGS-$(__X86__) = -arch i386
ARCH_FLAGS += $(ARCH_FLAGS-1)
# The following value is defined in defaults.mk.
ARCH_FLAGS += -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)
ifndef MACSDK
MACSDK := $(shell /usr/bin/xcrun --sdk macosx --show-sdk-path)
ifeq ($(MACSDK),)
$(error Could not find MacOSX SDK)
endif
export MACSDK
endif
ARCH_FLAGS += -isysroot $(MACSDK)
endif
#############################################################################
# toolchain-specific variables
ifneq (,$(filter $(COMPILER_NAME),gcc clang))
# file extensions
A = .a
B = $(SUFF64)
O = .o
II = .i
# toolchain output switches
OBJSW = -o # with space
OUTAR =
OUTII = -o # with space
OUTSW = -o # with space
ifdef __MAC__
OUTMAP = -Wl,-map,
else
OUTMAP = -Wl,-Map,
endif
# misc switches
AROPT = rc
CPPONLY = -E
FORCEC = -xc
NORTTI = -fno-rtti
ifdef __MAC__
OUTDLL = -dynamiclib
else
OUTDLL = --shared
endif
# utilities
CCACHE-$(USE_CCACHE) = ccache
ifeq ($(COMPILER_NAME),clang)
_CC = clang
_CXX = clang++
else
_CC = gcc
_CXX = g++
ifdef USE_GOLD
GOLD = -fuse-ld=gold
endif
endif
AR = $(CROSS_PREFIX)ar$(HOST_EXE) $(AROPT)
CC = $(CCACHE-1) $(CROSS_PREFIX)$(_CC)$(HOST_EXE) $(ARCH_FLAGS)
CCL = $(CROSS_PREFIX)$(_CXX)$(HOST_EXE) $(ARCH_FLAGS) $(GOLD)
CXX = $(CCACHE-1) $(CROSS_PREFIX)$(_CXX)$(HOST_EXE) $(ARCH_FLAGS)
else ifeq ($(COMPILER_NAME),vc)
# file extensions
A = .lib
B = $(SUFF64).exe
O = .obj
II = .i
# toolchain output switches
OBJSW = /Fo
OUTAR = /OUT:
OUTII = /Fi
OUTSW = /OUT:
OUTMAP = /map:
# misc switches
CPPONLY = /P
FORCEC = /TC
NOLOGO = /nologo
NORTTI = /GR-
OUTDLL = /DLL
# utilities
AR = $(MSVC_BIN)/lib.exe $(NOLOGO)
CC = $(MSVC_BIN)/cl.exe $(NOLOGO)
CCL = $(MSVC_BIN)/link.exe $(NOLOGO)
CXX = $(CC)
endif
##############################################################################
# target-specific cflags/ldflags
ifneq (,$(filter $(COMPILER_NAME),gcc clang))
# system cflags
CC_DEFS += $(PROCDEF)
ifdef __MAC__
CC_DEFS += __MAC__
else
CC_DEFS += __LINUX__
endif
# pic-related flags
# Note: this variable may be overridden in other parts of the build
PIC = -fPIC
ifdef __MAC__
LDPIE = $(PIC) -Wl,-pie
else
LDPIE = $(PIC) -pie
endif
# common cflags
CC_DEFS += $(DEF64)
CC_DEFS += $(DEFX86)
CC_F += $(PIC)
CC_F += -fdiagnostics-show-option
CC_F += -fno-strict-aliasing
CC_F += -fvisibility=hidden
CC_F += -fwrapv
CC_INCP += $(I)
CC_W += -Wall
CC_W += -Wextra
CC_W += -Wformat=2
CC_W += -Werror=format-security
CC_W += -Werror=format-nonliteral
CC_W += -Wshadow
CC_W += -Wunused
CC_WNO += -Wno-format-y2k
CC_WNO += -Wno-missing-field-initializers
CC_WNO += -Wno-sign-compare
CC_X += -g
CC_X += -pipe
# enable c++11
CXXSTD = -std=c++11
CXX_F += -fvisibility-inlines-hidden
CXX_WNO += -Wno-invalid-offsetof
# system-specific cflags
ifeq ($(COMPILER_NAME),clang) # mac/android
# 'cc -dumpversion' always reports 4.2.1 for clang
# https://stackoverflow.com/questions/12893731/why-does-clang-dumpversion-report-4-2-1
# clang is extra picky - need to add some warning supressions
# must eventually get rid of most of these
CC_WNO += -Wno-char-subscripts
CC_WNO += -Wno-dynamic-class-memaccess
CC_WNO += -Wno-int-to-pointer-cast
CC_WNO += -Wno-invalid-source-encoding
CC_WNO += -Wno-logical-not-parentheses
CC_WNO += -Wno-logical-op-parentheses
CC_WNO += -Wno-null-conversion
CC_WNO += -Wno-nullability-completeness
CC_WNO += -Wno-parentheses-equality
CC_WNO += -Wno-self-assign
CC_WNO += -Wno-unused-const-variable
CC_WNO += -Wno-unused-function
CC_WNO += -Wno-unused-private-field
CC_WNO += -Wno-unused-variable
CC_WNO += -Wno-varargs
CC_F += -fno-caret-diagnostics
else # (arm)linux
# get gcc version
ifndef _GCC_VERSION
_GCC_VERSION:=$(wordlist 1,2,$(subst ., ,$(shell $(CC) -dumpversion)))
export _GCC_VERSION
endif
GCC_VERSION=$(firstword $(_GCC_VERSION)).$(lastword $(_GCC_VERSION))
CC_WNO += -Wno-unused-local-typedefs
CC_F += -fno-diagnostics-show-caret
CC_DEFS-$(call gte,$(GCC_VERSION),5.0) += _GLIBCXX_USE_CXX11_ABI=0
CC_W-$(call gte,$(GCC_VERSION),7.0) += -Wimplicit-fallthrough=0
CXX_WNO-$(call gte,$(GCC_VERSION),8.0) += -Wno-class-memaccess
# suppress warning about ABI change in GCC 4.4
CC_WNO-$(__ARMLINUX__) += -Wno-psabi
endif
# optimization cflags
ifdef NDEBUG
CC_F += -fdata-sections
CC_F += -ffunction-sections
ifndef __ASAN__
CC_F += -fomit-frame-pointer
endif
# stack protector
ifdef __TARGET_MAC_HOST_LINUX__
# disable stack protector for our osxcross toolchain (we check
# against __TARGET_MAC_HOST_LINUX__ since it is hard to check
# for version number in clang).
else ifeq ($(call gte,$(GCC_VERSION),4.9),1)
CC_F += -fstack-protector-strong
else
CC_F += -fstack-protector
endif
CC_DEFS += NDEBUG
CC_DEFS += _FORTIFY_SOURCE=2
else
CC_DEFS += _DEBUG
endif
# system-specific ldflags
ifdef __LINUX__
LDFLAGS += -Wl,--build-id
LDFLAGS += -Wl,--gc-sections
LDFLAGS += -Wl,--warn-shared-textrel
NO_UNDEFS = -Wl,--no-undefined
DLL_W += $(NO_UNDEFS)
else ifdef __MAC__
LDFLAGS += -Wl,-dead_strip
ifndef __TARGET_MAC_HOST_LINUX__
DLL_X += -compatibility_version 1.0
DLL_X += -current_version 1.0
DLL_X += -single_module
endif
endif
# common linker/compiler flags
ifdef NDEBUG
CCOPT += -O2
ifdef __LINUX__
LDOPT += -Wl,-O1
endif
endif
# AddressSanitizer flags
ifdef __ASAN__
CC_DEFS += __ASAN__
CC_F += -fno-omit-frame-pointer
CC_F += -fsanitize=address
LDFLAGS += -fsanitize=address
export LSAN_OPTIONS=suppressions=$(IDA)etc/bin/known_leaks.txt:detect_leaks=0
endif
# final compiler flags
CC_F += $(CC_F-1)
CC_W += $(CC_W-1)
CC_WNO += $(CC_WNO-1)
CXX_WNO += $(CXX_WNO-1)
CC_DEFS += $(CC_DEFS-1)
CC_INCP += $(CC_INCP-1)
CC_D += $(addprefix -D,$(CC_DEFS))
CC_I += $(addprefix -I,$(CC_INCP))
# the -Wno-* flags must come after the -W enabling flags
WARNS = $(sort $(CC_W)) $(sort $(CC_WNO))
CFLAGS += $(sort $(CC_X))
CFLAGS += $(CCOPT)
CFLAGS += $(sort $(CC_I))
CFLAGS += $(sort $(CC_D))
CFLAGS += $(sort $(CC_F))
CFLAGS += $(WARNS)
CFLAGS += $(PTHR_SWITCH)
# for warning suppression, override the WARNS variable with NOWARNS:
# $(TARGET): WARNS = $(NOWARNS)
NOWARNS = -w
# dll linker flags
DLLFLAGS += $(DLL_W) $(DLL_X)
else ifeq ($(COMPILER_NAME),vc)
# for warning suppression, override the WARNS variable with NOWARNS:
# $(TARGET): WARNS = $(NOWARNS)
NOWARNS = -w -wd4702 -wd4738
# optimization ldflags
LDOPT += /DEBUG
ifdef NDEBUG
LDOPT += /INCREMENTAL:NO /OPT:ICF /OPT:REF
endif
# set c runtime to use
ifdef NDEBUG
ifdef USE_STATIC_RUNTIME
RUNTIME_LIBSW = /MT
else
RUNTIME_LIBSW = /MD
endif
else
ifdef USE_STATIC_RUNTIME
RUNTIME_LIBSW = /MTd
else
RUNTIME_LIBSW = /MDd
endif
endif
# PDB options
PDBFLAGS = /PDB:$(PDBDIR)/
ifdef NDEBUG
PDBFLAGS += /PDBALTPATH:%_PDB%
endif
# Generate debug info (old style)
PDBFORMAT = /Z7
# final compiler flags
CC_DEFS += $(DEF64)
CC_DEFS += $(DEFX86)
CC_DEFS += $(CC_DEFS-1)
CC_INCP += $(CC_INCP-1)
CC_D += $(addprefix -D,$(CC_DEFS))
CC_I += $(addprefix -I,$(CC_INCP))
CFGFILE = @$(IDA)$(SYSDIR).cfg
CFLAGS += $(CFGFILE)
CFLAGS += $(RUNTIME_LIBSW)
CFLAGS += $(PDBFORMAT)
CFLAGS += /Brepro
CFLAGS += $(sort $(CC_I))
CFLAGS += $(sort $(CC_D))
CFLAGS += $(sort $(CC_F))
CFLAGS += $(WARNS)
# final linker flags
LDFLAGS += /Brepro
LDFLAGS += $(PDBFLAGS)
LDFLAGS += /ERRORREPORT:QUEUE
ifdef __X86__
LDFLAGS += /LARGEADDRESSAWARE
endif
ifdef __XPCOMPAT__
XPSUBSYS-$(__X64__) = /SUBSYSTEM:CONSOLE,5.02
XPSUBSYS-$(__X86__) = /SUBSYSTEM:CONSOLE,5.01
LDFLAGS += $(XPSUBSYS-1)
endif
endif
# to enable obsolete functions, disable the NO_OBSOLETE_FUNCS variable:
# $(TARGET): NO_OBSOLETE_FUNCS =
NO_OBSOLETE_FUNCS = NO_OBSOLETE_FUNCS
CC_DEFS += $(NO_OBSOLETE_FUNCS)
CXXFLAGS += $(CXXSTD)
CXXFLAGS += $(CFLAGS)
CXXFLAGS += $(sort $(CXX_F))
CXXFLAGS += $(sort $(CXX_WNO))
LDFLAGS += $(LDOPT)
#############################################################################
ifdef __X86__
DEFX86 = __X86__
endif
ifdef __EA64__
SUFF64=64
ADRSIZE=64
DEF64 = __EA64__
else
ADRSIZE=32
endif
ifdef NDEBUG
OPTSUF=_opt
endif
ifdef IDAHOME
EXTRASUF=_home
IDAHOME_PROCESSORS=pc arm ppc mips mc68k
else
ifdef USE_STATIC_RUNTIME
EXTRASUF=_s
endif
endif
#############################################################################
SYSDIR=$(TARGET_PROCESSOR_NAME)_$(SYSNAME)_$(COMPILER_NAME)_$(ADRSIZE)$(OPTSUF)$(EXTRASUF)
# libraries directory
LIBDIR=$(IDA)lib/$(TARGET_PROCESSOR_NAME)_$(SYSNAME)_$(COMPILER_NAME)_$(ADRSIZE)$(EXTRASUF)
# object files directory (using ?= to allow overriding)
OBJDIR?=obj/$(SYSDIR)
# PDB files directory
PDBDIR=$(IDA)pdb/$(TARGET_PROCESSOR_NAME)_$(SYSNAME)_$(COMPILER_NAME)_$(ADRSIZE)$(EXTRASUF)
# output directory for target platform
R=$(IDA)bin/
# input directory with existing build utilities
RS=$(IDA)bin/
# _ida.hlp placed in main tool directory
HI=$(RS)
# help source
HS=.hls
# help headers
HH=.hhp
# include,help and other directories are common for all platforms and compilers:
I =$(IDA)include/
C =$(R)cfg/
RI=$(R)idc/
F=$(OBJDIR)/
L=$(LIBDIR)/
DUMB=$(L)dumb$(O)
HELP=$(L)help$(O)
HLIB=$(HI)_ida.hlp
# to be used like this:
# $(L)va$(A): $(call lib, $(VA_OBJS))
lib=$(1); $(strip $(QARf)$(AR) $(OUTAR)$$@ $$^)
# to be used like this: $(call _link_exe, target, objs, libs)
_link_exe=$(strip $(QCCL)$(CCL) $(OUTSW)$(1) $(2) $(3) $(LDFLAGS) $(STDLIBS))
# to be used like this: $(call link_exe, objs, libs)
link_exe=$(call _link_exe,$@,$(1),$(2))
# to be used like this: $(call _link_dll, target, objs, libs)
_link_dll=$(strip $(QCCL)$(CCL) $(OUTDLL) $(DLLFLAGS) $(OUTSW)$(1) $(2) $(3) $(LDFLAGS) $(STDLIBS))
# to be used like this: $(call link_dll, objs, libs)
link_dll=$(call _link_dll,$@,$(1),$(2))
# to be used like this: $(call link_dumb, target, libs, objs)
link_dumb=$(3) $(patsubst %,$(L)%$(A),$(2)); $(strip $(QCCLf)$(CCL) $(OUTSW)$(1) $(LDFLAGS) $(3) $(patsubst %,$(L)%$(A),$(2)) $(STDLIBS))
# to be used like this:
# target: $(call dumb_target, libs, objs) extra_ldflags
dumb_target=$(call link_dumb,$$@,$(1),$(2) $(DUMB))
# to be used like this:
# $(R)%$(B): $(F)%$(O) $(call dumb_pattern, libs, objs) extra_ldflags
dumb_pattern=$(call link_dumb,$$@ $$<,$(1),$(2) $(DUMB))
# to be used like this:
# OBJS += $(call objs,obj1 obj2 obj3 ...)
objs=$(addprefix $(F),$(addsuffix $(O),$(1)))
# output name for module dll
module_dll=$(BIN_PATH)$(1)$(SUFF64)$(DLLEXT)
# output name for server executable
server_exe=$(R)dbgsrv/$(1)
ifeq ($(or $(M),$(MM),$(MMH),$(MO),$(MMO),$(MMHO)),1)
BUILD_IDA = 1
endif
ifeq ($(or $(M32),$(MM),$(MO32),$(MMO)),1)
BUILD_DBGSRV = 1
endif
# target-os specific variables
ifdef __NT__
DLLEXT=.dll
else ifdef __MAC__
DLLEXT=.dylib
else
DLLEXT=.so
endif
# build system commands
ifeq ($(OS),Windows_NT)
CP=cp -f --preserve=all
MKDIR=-@mkdir
AWK=gawk
else
CP=cp -f
MKDIR=-@mkdir 2>/dev/null
AWK=awk
endif
RM=rm -f
MV=mv
# used to silence some makefile commands
# run 'make Q=' to prevent commands from being silenced
Q?=@
# some makefiles rebuild targets when the makefile itself changes.
# this makes debugging makefiles a pain.
# run 'make MAKEFILE_DEP=' to disable this behaviour.
MAKEFILE_DEP?=makefile
# libida-related
# Note: $(IDALIB) should be used in the dependency list
# $(LINKIDA) should be used in the link command
ifdef __NT__
# Note: on Windows, ida.lib does not have a "64" suffix for ea64
IDALIB = $(L)ida$(A)
LINKIDA = $(IDALIB)
else
IDALIB = $(L)libida$(SUFF64)$(DLLEXT)
LINKIDA = -L$(L) -lida$(SUFF64)
endif
# simplify command echo
ifdef IDAMAKE_SIMPLIFY
ifeq ($(Q),@)
DO_IDAMAKE_SIMPLIFY=1
endif
endif
ifdef DO_IDAMAKE_SIMPLIFY
ifdef IDAMAKE_SIMPLIFY_NO_COLOR
qcolor=$(1)
else
ifeq ($(OS),Windows_NT)
qcolor=-e #
endif
qcolor+="\033[1;34m$(1)\033[0m"
endif
QCXX = @echo $(call qcolor,compile) $< && #
QCC = @echo $(call qcolor,compile) $< && #
QASM = @echo $(call qcolor,asm) $< && #
QARf = @echo $(call qcolor,lib) $$@ && #
QCCL = @echo $(call qcolor,link) $@ && #
QCCLf = @echo $(call qcolor,link) $$@ && #
endif
# simple build rules
CONLY?=-c
$(F)%$(O): %.cpp
$(strip $(QCXX)$(CXX) $(CXXFLAGS) $(NORTTI) $(CONLY) $(OBJSW)$@ $<)
$(F)%$(O): %.c
$(strip $(QCC)$(CC) $(CFLAGS) $(CONLY) $(OBJSW)$@ $(FORCEC) $<)
$(C)%.cfg: %.cfg
$(CP) $? $@
# http://www.cmcrossroads.com/article/printing-value-makefile-variable
print-%:
@echo $* = "$($*)"
@echo $*\'s origin is $(origin $*)
#############################################################################
.PHONY: all test cfg includes
# Force make to delete the target if the rule to build it fails
.DELETE_ON_ERROR:

294
idasdk75/dbg/arm_debmod.cpp Normal file
View File

@@ -0,0 +1,294 @@
#include <pro.h>
#include <nalt.hpp>
#include "arm_debmod.h"
#ifdef ENABLE_LOWCNDS
inline bool has_armv5(void) { return true; }
static arm_debmod_t *ssmod; // pointer to the current debugger module
#endif
#include "arm_regs.hpp"
#include "deb_arm.hpp"
//--------------------------------------------------------------------------
arm_debmod_t::arm_debmod_t()
{
static const uchar bpt[] = ARM_BPT_CODE;
bpt_code.append(bpt, sizeof(bpt));
sp_idx = R_SP;
pc_idx = R_PC;
lr_idx = R_LR;
sr_idx = R_PSR;
nregs = qnumber(arm_registers);
is_xscale = false;
for ( size_t i = 0; i < 2; i++ )
{
databpts[i] = BADADDR;
codebpts[i] = BADADDR;
dbptypes[i] = -1;
cbptypes[i] = -1;
}
dbcon = 0;
set_platform("linux");
}
//--------------------------------------------------------------------------
int idaapi arm_debmod_t::dbg_is_ok_bpt(bpttype_t type, ea_t /*ea*/, int len)
{
if ( type == BPT_SOFT )
return BPT_OK;
if ( !is_xscale )
return BPT_BAD_TYPE; // hardware bpts are supported only for xScale
// For some reason hardware instruction breakpoints do not work
if ( type == BPT_EXEC )
return BPT_BAD_TYPE;
if ( len > 4 )
return BPT_BAD_LEN;
bool ok = databpts[0] == BADADDR || databpts[1] == BADADDR;
return ok ? BPT_OK : BPT_TOO_MANY;
}
//--------------------------------------------------------------------------
bool arm_debmod_t::add_hwbpt(bpttype_t type, ea_t ea, int len)
{
// msg("add_hwbpt %d %a %d\n", type, ea, len);
if ( !is_xscale || len > 4 )
return false;
if ( !init_hwbpt_support() )
return false;
if ( type == BPT_EXEC )
{
if ( codebpts[0] != BADADDR && codebpts[1] != BADADDR )
return false;
int slot = codebpts[0] != BADADDR;
codebpts[slot] = ea;
cbptypes[slot] = type;
}
else
{
if ( databpts[0] != BADADDR && databpts[1] != BADADDR )
return false;
int slot = databpts[0] != BADADDR;
int bits;
switch ( type )
{
case BPT_WRITE:
bits = 1; // store only
break;
case BPT_RDWR:
bits = 2; // load/store
break;
// BPT_READ: // load only
// bits = 3;
// break;
default:
return false;
}
databpts[slot] = ea;
dbptypes[slot] = type;
dbcon |= bits << (slot*2);
}
return enable_hwbpts();
}
//--------------------------------------------------------------------------
bool arm_debmod_t::del_hwbpt(ea_t ea, bpttype_t type)
{
// msg("del_hwbpt %a\n", ea);
if ( databpts[0] == ea && dbptypes[0] == type )
{
databpts[0] = BADADDR;
dbcon &= ~3;
}
else if ( databpts[1] == ea && dbptypes[1] == type )
{
databpts[1] = BADADDR;
dbcon &= ~(3<<2);
}
else if ( codebpts[0] == ea && cbptypes[0] == type )
{
codebpts[0] = BADADDR;
}
else if ( codebpts[1] == ea && cbptypes[1] == type )
{
codebpts[1] = BADADDR;
}
else
{
return false;
}
return enable_hwbpts();
}
//--------------------------------------------------------------------------
void arm_debmod_t::cleanup_hwbpts()
{
databpts[0] = BADADDR;
databpts[1] = BADADDR;
codebpts[0] = BADADDR;
codebpts[1] = BADADDR;
dbcon = 0;
// disable all bpts
if ( is_xscale )
disable_hwbpts();
}
//--------------------------------------------------------------------------
int arm_debmod_t::finalize_appcall_stack(
call_context_t &ctx,
regval_map_t &regs,
bytevec_t &/*stk*/)
{
regs[lr_idx].ival = ctx.ctrl_ea;
// return addrsize as the adjustment factor to add to sp
// we do not need the return address, that's why we ignore the first 4
// bytes of the prepared stack image
return debapp_attrs.addrsize;
}
//--------------------------------------------------------------------------
int arm_debmod_t::get_regidx(const char *regname, int *clsmask)
{
return arm_get_regidx(clsmask, regname);
}
#ifdef ENABLE_LOWCNDS
//--------------------------------------------------------------------------
static const regval_t &idaapi arm_getreg(const char *name, const regval_t *regvals)
{
int idx = ssmod->get_regidx(name, NULL);
QASSERT(30182, idx >= 0 && idx < ssmod->nregs);
return regvals[idx];
}
//--------------------------------------------------------------------------
static uint32 idaapi arm_get_long(ea_t ea)
{
uint32 v = -1;
ssmod->dbg_read_memory(ea, &v, sizeof(v), NULL);
return v;
}
//--------------------------------------------------------------------------
static uint16 idaapi arm_get_word(ea_t ea)
{
uint16 v = -1;
ssmod->dbg_read_memory(ea, &v, sizeof(v), NULL);
return v;
}
//--------------------------------------------------------------------------
static uint8 idaapi arm_get_byte(ea_t ea)
{
uint8 v = -1;
ssmod->dbg_read_memory(ea, &v, sizeof(v), NULL);
return v;
}
//----------------------------------------------------------------------
// stripped down version of get_dtype_size()
static size_t idaapi arm_get_dtype_size(op_dtype_t dtype)
{
switch ( dtype )
{
case dt_byte: return 1; // 8 bit
case dt_word:
case dt_half: return 2; // 16 bit
case dt_dword:
case dt_float: return 4; // 4 byte
case dt_qword:
case dt_double: return 8; // 8 byte
default: return 0;
}
}
//--------------------------------------------------------------------------
// since arm does not have a single step facility, we have to emulate it
// with a temporary breakpoint.
drc_t arm_debmod_t::dbg_perform_single_step(debug_event_t *dev, const insn_t &insn)
{
// read register values
regvals_t values;
values.resize(nregs);
drc_t drc = dbg_read_registers(dev->tid, ARM_RC_GENERAL, values.begin(), NULL);
if ( drc <= DRC_NONE )
return drc;
static const opinfo_helpers_t oh =
{
arm_getreg,
arm_get_byte,
arm_get_word,
arm_get_long,
arm_get_dtype_size,
NULL, // has_insn_cf_chg not needed
};
// calculate the address of the next executed instruction
lock_begin();
ssmod = this;
ea_t next = calc_next_exec_insn(insn, values.begin(), oh, false); // TODO pass is_mprofile parameter
ssmod = NULL;
lock_end();
// BADADDR means that the execution flow is linear
if ( next == BADADDR )
{
next = insn.ea + insn.size;
if ( (values[sr_idx].ival & BIT5) != 0 ) // thumb?
next |= 1;
}
// safety check: self jumping instruction cannot be single stepped
if ( (next & ~1) == insn.ea )
return DRC_FAILED;
// add a breakpoint there
update_bpt_info_t ubi;
ubi.ea = next;
ubi.type = BPT_SOFT;
ubi.code = 0;
int nbpts;
drc = dbg_update_bpts(&nbpts, &ubi, 1, 0, NULL);
if ( drc != DRC_OK || nbpts == 0 )
return drc != DRC_OK ? drc : DRC_FAILED;
drc = resume_app_and_get_event(dev);
// clean up: delete the temporary breakpoint
ubi.ea &= ~1; // del_bpt requires an even address
drc_t drc2 = dbg_update_bpts(&nbpts, &ubi, 0, 1, NULL);
if ( drc2 != DRC_OK || nbpts == 0 )
{
msg("%a: failed to remove single step bpt?!\n", ubi.ea);
drc = drc2 != DRC_OK ? drc2 : DRC_FAILED;
}
// the caller expects to see STEP after us:
if ( drc == DRC_OK )
dev->set_eid(STEP);
return drc;
}
#endif // ENABLE_LOWCNDS
//--------------------------------------------------------------------------
void arm_debmod_t::adjust_swbpt(ea_t *p_ea, int *p_len)
{
ea_t &ea = *p_ea;
if ( (ea & 1) != 0 ) // T bit is set, use a thumb breakpoint
{
ea--;
*p_len = 2;
}
}

66
idasdk75/dbg/arm_debmod.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef __ARM_DEBMOD__
#define __ARM_DEBMOD__
#include "deb_arm.hpp"
#include "debmod.h"
//--------------------------------------------------------------------------
class arm_debmod_t : public debmod_t
{
typedef debmod_t inherited;
protected:
bool is_xscale;
ea_t databpts[2];
ea_t codebpts[2];
bpttype_t dbptypes[2];
bpttype_t cbptypes[2];
int dbcon;
int lr_idx;
int sr_idx;
public:
arm_debmod_t();
void cleanup_hwbpts();
bool del_hwbpt(ea_t ea, bpttype_t type);
bool add_hwbpt(bpttype_t type, ea_t ea, int len);
ea_t is_hwbpt_triggered(thid_t id, bool is_stepping);
inline bool active_databpts(void)
{
return databpts[0] != BADADDR || databpts[1] != BADADDR;
}
inline bool active_codebpts(void)
{
return codebpts[0] != BADADDR || codebpts[1] != BADADDR;
}
inline bool active_hwbpts(void)
{
return active_databpts() || active_codebpts();
}
// overridden base class functions
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) override;
virtual int finalize_appcall_stack(call_context_t &ctx, regval_map_t &regs, bytevec_t &stk) override;
// new virtial functions
virtual bool init_hwbpt_support() newapi { return true; }
virtual bool disable_hwbpts() newapi { return false; }
virtual bool enable_hwbpts() newapi { return false; }
virtual bool refresh_hwbpts() newapi { return false; }
virtual int get_regidx(const char *regname, int *clsmask) override;
virtual void adjust_swbpt(ea_t *p_ea, int *p_len) override;
protected:
#ifdef ENABLE_LOWCNDS
virtual drc_t dbg_perform_single_step(debug_event_t *dev, const insn_t &insn) override;
#endif
};
bool is_32bit_thumb_insn(uint16 code);
#endif

View File

@@ -0,0 +1,107 @@
#include <set>
#include <idp.hpp>
#include <dbg.hpp>
#include <loader.hpp>
#include <segregs.hpp>
#include <segment.hpp>
#include "deb_arm.hpp"
#include "arm_regs.cpp"
//--------------------------------------------------------------------------
int is_arm_valid_bpt(bpttype_t type, ea_t ea, int len)
{
if ( type == BPT_SOFT )
{
if ( (ea & 1) != 0 )
return BPT_BAD_ADDR;
}
else
{
if ( type != BPT_RDWR // type is good?
&& type != BPT_WRITE
&& type != BPT_EXEC )
{
return BPT_BAD_TYPE;
}
if ( (ea & (len-1)) != 0 ) // alignment is good?
return BPT_BAD_ALIGN;
if ( len != 1 )
{
warning("AUTOHIDE REGISTRY\n"
"xScale supports only 1 byte length hardware breakpoints");
return BPT_BAD_LEN;
}
}
return BPT_OK;
}
//--------------------------------------------------------------------------
// if bit0 is set, ensure that thumb mode
// if bit0 is clear, ensure that arm mode
static void handle_arm_thumb_modes(ea_t ea)
{
bool should_be_thumb = (ea & 1) != 0;
bool is_thumb = processor_t::get_code16_mode(ea);
if ( should_be_thumb != is_thumb )
processor_t::set_code16_mode(ea, should_be_thumb);
}
//--------------------------------------------------------------------------
static easet_t pending_addresses;
static ssize_t idaapi dbg_callback(void *, int code, va_list)
{
// we apply thumb/arm switches when the process is suspended.
// it is quite late (normally we should do it as soon as the corresponding
// segment is created) but i did not manage to make it work.
// in the segm_added event the addresses are not enabled yet,
// so switching modes fails.
if ( code == dbg_suspend_process && !pending_addresses.empty() )
{
for ( easet_t::iterator p=pending_addresses.begin();
p != pending_addresses.end();
++p )
{
handle_arm_thumb_modes(*p);
}
pending_addresses.clear();
}
return 0;
}
//--------------------------------------------------------------------------
// For ARM processors the low bit means 1-thumb, 0-arm mode.
// The following function goes over the address list and sets the mode
// in IDA database according to bit0. It also resets bit0 for all addresses.
void set_arm_thumb_modes(ea_t *addrs, int qty)
{
for ( int i=0; i < qty; i++ )
{
ea_t ea = addrs[i];
segment_t *s = getseg(ea);
if ( s == NULL )
pending_addresses.insert(ea);
else
handle_arm_thumb_modes(ea);
addrs[i] = ea & ~1;
}
}
//--------------------------------------------------------------------------
void processor_specific_init(void)
{
hook_to_notification_point(HT_DBG, dbg_callback);
}
//--------------------------------------------------------------------------
void processor_specific_term(void)
{
unhook_from_notification_point(HT_DBG, dbg_callback);
pending_addresses.clear();
}

213
idasdk75/dbg/arm_regs.cpp Normal file
View File

@@ -0,0 +1,213 @@
#include "arm_regs.hpp"
//-------------------------------------------------------------------------
// NOTE: keep in sync with register_class_arm_t
const char *arm_register_classes[] =
{
"General registers",
"VFP registers",
NULL
};
#ifndef __EA64__
//-------------------------------------------------------------------------
static const char *const psr[] =
{
"MODE", // 0
"MODE", // 1
"MODE", // 2
"MODE", // 3
"MODE", // 4
"T", // 5
"F", // 6
"I", // 7
"A", // 8
"E", // 9
"IT", // 10
"IT", // 11
"IT", // 12
"IT", // 13
"IT", // 14
"IT", // 15
"GE", // 16
"GE", // 17
"GE", // 18
"GE", // 19
NULL, // 20
NULL, // 21
NULL, // 22
NULL, // 23
"J", // 24
"IT2", // 25 additional bits of IT
"IT2", // 26 additional bits of IT
"Q", // 27
"V", // 28
"C", // 29
"Z", // 30
"N", // 31
};
//-------------------------------------------------------------------------
static const char *const vfp_format[] =
{
"VFP_1_double",
};
#else
//-------------------------------------------------------------------------
static const char *const psr[] =
{
"M", // 0 AArch32 mode that an exception was taken from
"M", // 1
"M", // 2
"M", // 3
"M", // 4 Execution state that the exception was taken from
"T", // 5 T32 Instruction set state bit
"F", // 6 FIQ mask bit
"I", // 7 IRQ mask bit
"A", // 8 Asynchronous data abort mask bit
"E", // 9 Endianness Execution State bit
"IT", // 10 If-Then
"IT", // 11
"IT", // 12
"IT", // 13
"IT", // 14
"IT", // 15
"GE", // 16 Greater than or Equal flags
"GE", // 17
"GE", // 18
"GE", // 19
"IL", // 20 Illegal Execution State bit
NULL, // 21
NULL, // 22
NULL, // 23
NULL, // 24
"IT2", // 25 If-Then
"IT2", // 26
"Q", // 27 Cumulative saturation bit
"V", // 28 oVerflow condition flag
"C", // 29 Carry condition flag
"Z", // 30 Zero condition flag
"N", // 31 Negative condition flag
};
#endif
//-------------------------------------------------------------------------
// NOTE: keep in sync with register_arm_t
register_info_t arm_registers[] =
{
#ifndef __EA64__
// General registers
{ "R0", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R1", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R2", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R3", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R4", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R5", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R6", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R7", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R8", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R9", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R10", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R11", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "R12", REGISTER_ADDRESS|REGISTER_FP, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "SP", REGISTER_ADDRESS|REGISTER_SP, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "LR", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "PC", REGISTER_ADDRESS|REGISTER_IP, ARM_RC_GENERAL, dt_dword, NULL, 0 },
{ "PSR", 0, ARM_RC_GENERAL, dt_dword, psr, 0xF800007F },
// VFP registers
{ "D0", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D1", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D2", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D3", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D4", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D5", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D6", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D7", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D8", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D9", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D10", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D11", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D12", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D13", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D14", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D15", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D16", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D17", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D18", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D19", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D20", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D21", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D22", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D23", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D24", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D25", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D26", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D27", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D28", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D29", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D30", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "D31", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
{ "FPSCR", 0, ARM_RC_VFP, dt_dword, NULL, 0 },
#else
// General registers
{ "X0", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X1", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X2", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X3", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X4", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X5", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X6", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X7", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X8", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X9", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X10", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X11", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X12", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X13", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X14", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X15", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X16", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X17", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X18", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X19", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X20", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X21", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X22", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X23", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X24", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X25", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X26", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X27", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X28", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X29", REGISTER_ADDRESS|REGISTER_FP, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "X30", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "SP", REGISTER_ADDRESS|REGISTER_SP, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "PC", REGISTER_ADDRESS|REGISTER_IP, ARM_RC_GENERAL, dt_qword, NULL, 0 },
{ "PSR", 0, ARM_RC_GENERAL, dt_dword, psr, 0xF8000000 },
#endif
};
CASSERT(qnumber(arm_registers) == ARM_NREGS);
//-------------------------------------------------------------------------
int arm_get_regidx(int *clsmask, const char *regname)
{
for ( size_t i = 0; i < qnumber(arm_registers); i++ )
{
if ( strieq(regname, arm_registers[i].name) )
{
if ( clsmask != NULL )
*clsmask = arm_registers[i].register_class;
return i;
}
}
return -1;
}
//-------------------------------------------------------------------------
int arm_get_regclass(int idx)
{
if ( idx >= 0 && idx < qnumber(arm_registers) )
return arm_registers[idx].register_class;
return 0;
}

136
idasdk75/dbg/arm_regs.hpp Normal file
View File

@@ -0,0 +1,136 @@
#pragma once
#include <pro.h>
#include <idd.hpp>
//-------------------------------------------------------------------------
#if defined(__LINUX__) && defined(__ARM__) && !defined(__EA64__)
# define __HAVE_ARM_VFP__
#endif
//-------------------------------------------------------------------------
// NOTE: keep in sync with arm_register_classes
enum register_class_arm_t
{
ARM_RC_GENERAL = 0x01, // General registers
ARM_RC_VFP = 0x02, // VFP registers
ARM_RC_ALL = ARM_RC_GENERAL
#ifdef __HAVE_ARM_VFP__
| ARM_RC_VFP
#endif
};
//-------------------------------------------------------------------------
// NOTE: keep in sync with arm_registers
enum register_arm_t
{
#ifndef __EA64__
// General registers
R_R0,
R_R1,
R_R2,
R_R3,
R_R4,
R_R5,
R_R6,
R_R7,
R_R8,
R_R9,
R_R10,
R_R11,
R_R12,
R_SP,
R_LR,
R_PC,
R_PSR,
// VFP registers
R_D0,
R_D1,
R_D2,
R_D3,
R_D4,
R_D5,
R_D6,
R_D7,
R_D8,
R_D9,
R_D10,
R_D11,
R_D12,
R_D13,
R_D14,
R_D15,
R_D16,
R_D17,
R_D18,
R_D19,
R_D20,
R_D21,
R_D22,
R_D23,
R_D24,
R_D25,
R_D26,
R_D27,
R_D28,
R_D29,
R_D30,
R_D31,
R_FPSCR,
#else
// General registers
R_R0,
R_R1,
R_R2,
R_R3,
R_R4,
R_R5,
R_R6,
R_R7,
R_R8,
R_R9,
R_R10,
R_R11,
R_R12,
R_R13,
R_R14,
R_R15,
R_R16,
R_R17,
R_R18,
R_R19,
R_R20,
R_R21,
R_R22,
R_R23,
R_R24,
R_R25,
R_R26,
R_R27,
R_R28,
R_R29,
R_LR,
R_SP,
R_PC,
R_PSR,
#endif
};
// Number of registers in arm and aarch64
#define ARM64_NREGS 34
#define ARM32_NREGS 50
#ifdef __EA64__
#define ARM_NREGS ARM64_NREGS
#else
#define ARM_NREGS ARM32_NREGS
#endif
//-------------------------------------------------------------------------
extern const char *arm_register_classes[];
extern register_info_t arm_registers[ARM_NREGS];
//-------------------------------------------------------------------------
int arm_get_regidx(int *clsmask, const char *regname);
int arm_get_regclass(int idx);

906
idasdk75/dbg/bin_search.cpp Normal file
View File

@@ -0,0 +1,906 @@
#include <pro.h>
#include "debmod.h"
//#define TEST
#ifdef TEST
static uchar memory[256];
static const int PAGESZ = 4;
static ssize_t read_page(ea_t ea, void *buf, size_t size, qstring *)
{
QASSERT(1517, (size % PAGESZ) == 0);
if ( ea >= sizeof(memory) )
return -1;
memcpy(buf, &memory[ea], size);
return size;
}
#else
static const int PAGESZ = 4096;
#define read_page(ea, buf, size, errbuf) mod->dbg_read_memory(ea, buf, size, errbuf)
#endif
static const int PAGE_HB = 1000; // page heartbeat counter
static const int TIME_HB = (RECV_TIMEOUT_PERIOD/1000) / 2;
// time period between heartbeats
//--------------------------------------------------------------------------
// memrchr is unavailable under Windows and MAC
#if defined(_WIN32) || defined(__MAC__)
// fixme: we need more optimized version
static void *local_memrchr(const void *s, int c, size_t n)
{
const unsigned char *start = (const unsigned char *)s;
const unsigned char *end = start + n - 1;
while ( end >= start )
{
if ( *end == c )
return (void *)end;
end--;
}
return NULL;
}
#else
#define local_memrchr memrchr
#endif
//--------------------------------------------------------------------------
class matcher_t
{
protected:
struct partmatch_t
{
ea_t match_ea; // starting address of the match
size_t ptn_idx; // index of the pattern
size_t ptn_off; // offset inside the pattern
};
typedef qlist<partmatch_t> partmatches_t;
// constructor arguments
ea_t *found_ea;
debmod_t *mod;
const compiled_binpat_vec_t &ptns;
int srch_flags;
qstring *errbuf; //lint !e958
uchar page[PAGESZ];
ea_t page_ea;
partmatches_t pmatches;
ea_t failed_ea;
// cache
intvec_t simple_ptns; // indexes of patterns w/o a mask and the search is case sensitive
intvec_t complex_ptns; // other patterns
// heartbeat
uint32 last_hb; // time in secs of the last heartbeat
matcher_t(
ea_t *_found_ea,
debmod_t *_mod,
const compiled_binpat_vec_t &_ptns,
int _srch_flags,
qstring *_errbuf)
: found_ea(_found_ea),
mod(_mod),
ptns(_ptns),
srch_flags(_srch_flags),
errbuf(_errbuf),
page_ea(BADADDR),
failed_ea(BADADDR)
{
for ( int i=0; i < ptns.size(); ++i )
{
const compiled_binpat_t &ptn = ptns[i];
if ( ptn.bytes.empty() )
continue;
if ( sense_case() && ptn.all_bytes_defined() ) //TODO: && !inf_is_wide_high_byte_first() - for servers
simple_ptns.push_back(i);
else
complex_ptns.push_back(i);
}
memset(page, 0, sizeof(page));
last_hb = get_secs(qtime64());
}
bool sense_case(void) const { return (srch_flags & BIN_SEARCH_CASE) != 0; }
bool check_break(void) const { return (srch_flags & BIN_SEARCH_NOBREAK) == 0; }
bool test_cancelled(void) const
{
struct ida_local tester_t : public exec_request_t
{
virtual ~tester_t() {}
virtual int idaapi execute(void)
{
return user_cancelled();
}
};
tester_t tester;
return execute_sync(tester, MFF_FAST);
}
void send_heartbeat(size_t *page_counter)
{
*page_counter += 1;
if ( *page_counter >= PAGE_HB )
{
*page_counter = 0;
uint32 now = get_secs(qtime64());
if ( now - last_hb >= TIME_HB )
{
mod->dmsg(""); // heartbeat
last_hb = now;
}
}
}
public:
DECLARE_VIRTUAL_DTOR(matcher_t)
{
found_ea = NULL;
mod = NULL;
errbuf = NULL;
}
virtual drc_t walk_memory_ranges(const ea_t srch_start_ea, const ea_t srch_end_ea) = 0;
drc_t search_memory_range(ea_t range_start_ea, ea_t range_end_ea)
{
if ( range_is_unreadable(range_start_ea) )
{
#ifndef TEST
mod->debdeb("dbg_bin_search memory range %a..%a is unreadable, skip it\n", range_start_ea, range_end_ea);
#endif
return DRC_FAILED;
}
return find(range_start_ea, range_end_ea);
}
virtual drc_t find(ea_t start_ea, ea_t end_ea) = 0;
bool match_pattern(
const uchar *page_ptr,
const compiled_binpat_t &ptn,
size_t ptn_off,
size_t nbytes) const
{
const uchar *image = ptn.bytes.begin() + ptn_off;
const uchar *mask = ptn.all_bytes_defined() ? NULL : ptn.mask.begin() + ptn_off;
for ( int i=0; i < nbytes; ++i, ++page_ptr, ++image )
{
uchar c = *page_ptr;
if ( mask != NULL )
{
if ( mask == SKIP_FF_MASK )
{
if ( *image == 0xFF )
continue;
}
else
{
if ( mask[i] == 0 )
continue;
}
}
uchar c2 = *image;
if ( sense_case() ? (c != c2) : (qtoupper(c) != qtoupper(c2)) )
return false;
}
return true;
}
ea_t get_failed_address(void) const { return failed_ea; }
private:
bool range_is_unreadable(ea_t range_start_ea)
{
uchar dummy;
return mod->dbg_read_memory(range_start_ea, &dummy, sizeof(dummy), NULL) != sizeof(dummy);
}
};
typedef janitor_t<matcher_t *> matcher_janitor_t;
template <> inline matcher_janitor_t::~janitor_t()
{
delete resource;
resource = NULL;
}
//--------------------------------------------------------------------------
class forward_matcher_t : public matcher_t
{
size_t last_off;
public:
forward_matcher_t(
ea_t *_found_ea,
debmod_t *_mod,
const compiled_binpat_vec_t &_ptns,
int _srch_flags,
qstring *_errbuf)
: matcher_t(_found_ea, _mod, _ptns, _srch_flags, _errbuf),
last_off(PAGESZ)
{}
//--------------------------------------------------------------------------
virtual drc_t walk_memory_ranges(const ea_t srch_start_ea, const ea_t srch_end_ea) override
{
meminfo_vec_t::const_iterator p=mod->old_ranges.begin();
ea_t range_start_ea = BADADDR;
for ( ; p < mod->old_ranges.end(); ++p )
{
if ( p->contains(srch_start_ea) )
{
range_start_ea = srch_start_ea;
break;
}
if ( p->start_ea > srch_start_ea )
break;
}
if ( range_start_ea == BADADDR )
{
if ( p == mod->old_ranges.end() || p->start_ea >= srch_end_ea )
return DRC_FAILED; // not found
range_start_ea = p->start_ea;
}
ea_t range_end_ea = srch_end_ea < p->end_ea ? srch_end_ea : p->end_ea;
drc_t drc = search_memory_range(range_start_ea, range_end_ea);
if ( drc != DRC_FAILED ) // not found
return drc;
for ( ++p; p < mod->old_ranges.end() && srch_end_ea >= p->end_ea; ++p )
{
range_start_ea = p->start_ea;
range_end_ea = srch_end_ea < p->end_ea ? srch_end_ea : p->end_ea;
drc = search_memory_range(range_start_ea, range_end_ea);
if ( drc != DRC_FAILED ) // not found
return drc;
}
return DRC_FAILED; // not found
}
//--------------------------------------------------------------------------
// find patterns in [start_ea, end_ea)
virtual drc_t find(ea_t start_ea, ea_t end_ea) override
{
page_ea = align_down(start_ea, PAGESZ);
ea_t page_off = start_ea - page_ea;
size_t page_counter = 0;
while ( page_ea < end_ea )
{
if ( check_break() && test_cancelled() )
return DRC_ERROR;
if ( read_page(page_ea, page, sizeof(page), errbuf) != sizeof(page) )
{
failed_ea = page_ea;
return DRC_ERROR;
}
last_off = end_ea - page_ea;
if ( last_off > PAGESZ )
last_off = PAGESZ;
// handle partial matches first
for ( partmatches_t::iterator p=pmatches.begin(); p != pmatches.end(); )
{
switch ( finalize_partial_match(*p) )
{
case DRC_OK: // found a match
return DRC_OK;
default:
case DRC_FAILED: // definitely failed
p = pmatches.erase(p);
break;
case DRC_NONE: // need to continue matching
++p;
break;
}
}
// try to find new matches
if ( match_simple_patterns(page_off) )
return DRC_OK;
if ( !complex_ptns.empty() )
{
while ( page_off < last_off )
{
if ( match_at(page_off) )
return DRC_OK;
page_off++;
}
}
page_ea += PAGESZ; // advance to the next page
page_off = 0;
send_heartbeat(&page_counter);
}
return DRC_FAILED;
}
private:
//--------------------------------------------------------------------------
// try to match complex patterns at PAGE_OFF
// too long patterns that do not fit the page will be matched partially
// if the partial match is ok, we will remember them
bool match_at(ea_t page_off)
{
const uchar *page_ptr = page + page_off;
size_t rest = last_off - page_off;
for ( intvec_t::const_iterator p=complex_ptns.begin();
p != complex_ptns.end();
++p )
{
const int &i = *p;
const compiled_binpat_t &ptn = ptns[i];
size_t vecsize = ptn.bytes.size();
size_t nbytes = qmin(rest, vecsize);
if ( !match_pattern(page_ptr, ptn, 0, nbytes) )
continue;
if ( vecsize <= rest )
{
*found_ea = page_ea + page_off;
return true; // fits the page, a simple comparison is enough
}
// remember partial match
partmatch_t pm;
pm.match_ea = page_ea + page_off;
pm.ptn_idx = i;
pm.ptn_off = nbytes;
pmatches.push_back(pm);
}
return false;
}
//--------------------------------------------------------------------------
// try to match simple patterns inside the page
// the partial match is processed as described above
bool match_simple_patterns(ea_t page_off)
{
for ( intvec_t::const_iterator p=simple_ptns.begin();
p != simple_ptns.end();
++p )
{
const int &i = *p;
const uchar *page_ptr = page + page_off;
size_t rest = last_off - page_off;
const bytevec_t &ptn_bytes = ptns[i].bytes;
size_t ptn_sz = ptn_bytes.size();
uchar ptn_ch = ptn_bytes[0];
const uchar *pold = page_ptr;
while ( rest > 0 )
{
const uchar *pnew = (uchar *)memchr(pold, ptn_ch, rest);
if ( pnew == NULL )
break;
rest -= (pnew - pold);
size_t nbytes = qmin(rest, ptn_sz);
if ( memcmp(pnew, ptn_bytes.begin(), nbytes) == 0 )
{
ea_t matched_ea = page_ea + (pnew - page);
if ( ptn_sz <= rest )
{
*found_ea = matched_ea;
return true;
}
// remember partial match
partmatch_t pm;
pm.match_ea = matched_ea;
pm.ptn_idx = i;
pm.ptn_off = nbytes;
pmatches.push_back(pm);
}
pold = pnew + 1;
rest -= 1;
}
}
return false;
}
//--------------------------------------------------------------------------
// try to finalize a partial match by matching the next part of the
// long pattern against the start of the PAGE. patterns that are still
// too long for matching may produce new partial matches.
drc_t finalize_partial_match(partmatch_t &pm)
{
const compiled_binpat_t &ptn = ptns[pm.ptn_idx];
size_t vecsize = ptn.bytes.size();
size_t ptn_rest = vecsize - pm.ptn_off;
size_t nbytes = qmin(ptn_rest, last_off);
if ( !match_pattern(page, ptn, pm.ptn_off, nbytes) )
return DRC_FAILED;
if ( ptn_rest <= last_off )
{
*found_ea = pm.match_ea;
return DRC_OK; // finalized the match
}
if ( last_off != PAGESZ )
return DRC_FAILED;
// remember a new partial match
pm.ptn_off += PAGESZ;
return DRC_NONE;
}
};
//--------------------------------------------------------------------------
class backward_matcher_t : public matcher_t
{
ea_t page_off;
public:
backward_matcher_t(
ea_t *_found_ea,
debmod_t *_mod,
const compiled_binpat_vec_t &_ptns,
int _srch_flags,
qstring *_errbuf)
: matcher_t(_found_ea, _mod, _ptns, _srch_flags, _errbuf),
page_off(0)
{}
//--------------------------------------------------------------------------
virtual drc_t walk_memory_ranges(const ea_t srch_start_ea, const ea_t srch_end_ea) override
{
meminfo_vec_t::const_iterator p=mod->old_ranges.end() - 1;
ea_t range_end_ea = BADADDR;
for ( ; p >= mod->old_ranges.begin(); --p )
{
if ( p->start_ea < srch_end_ea )
{
range_end_ea = srch_end_ea < p->end_ea ? srch_end_ea : p->end_ea;
break;
}
}
if ( range_end_ea == BADADDR )
return DRC_FAILED; // not found
ea_t range_start_ea = p->contains(srch_start_ea) ? srch_start_ea : p->start_ea;
drc_t drc = search_memory_range(range_start_ea, range_end_ea);
if ( drc != DRC_FAILED ) // not found
return drc;
for ( --p; p >= mod->old_ranges.begin() && srch_start_ea < p->end_ea; --p )
{
range_end_ea = p->end_ea;
range_start_ea = p->contains(srch_start_ea) ? srch_start_ea : p->start_ea;
drc = search_memory_range(range_start_ea, range_end_ea);
if ( drc != DRC_FAILED ) // not found
return drc;
}
return DRC_FAILED; // not found
}
//--------------------------------------------------------------------------
// find patterns in [start_ea, end_ea)
virtual drc_t find(ea_t start_ea, ea_t end_ea) override
{
page_ea = align_down(end_ea - 1, PAGESZ);
ea_t last_off = end_ea - page_ea;
size_t page_counter = 0;
while ( start_ea < page_ea + PAGESZ )
{
if ( check_break() && test_cancelled() )
return DRC_ERROR;
if ( read_page(page_ea, page, sizeof(page), errbuf) != sizeof(page) )
{
failed_ea = page_ea;
return DRC_ERROR;
}
page_off = page_ea < start_ea ? start_ea - page_ea : 0;
// handle partial matches first
for ( partmatches_t::iterator p=pmatches.begin(); p != pmatches.end(); )
{
switch ( finalize_partial_match(*p) )
{
case DRC_OK: // found a match
return DRC_OK;
default:
case DRC_FAILED: // definitely failed
p = pmatches.erase(p);
break;
case DRC_NONE: // need to continue matching
++p;
break;
}
}
// try to find new matches
if ( match_simple_patterns(last_off) )
return DRC_OK;
if ( !complex_ptns.empty() )
{
while ( page_off < last_off )
{
if ( match_before(last_off) )
return DRC_OK;
last_off--;
}
}
page_ea -= PAGESZ; // advance to the next page
last_off = PAGESZ;
send_heartbeat(&page_counter);
}
return DRC_FAILED;
}
private:
//--------------------------------------------------------------------------
// try to match all patterns before LAST_OFF
// too long patterns that do not fit the page will be matched partially
// if the partial match is ok, we will remember them
bool match_before(ea_t last_off)
{
size_t rest = last_off - page_off;
for ( intvec_t::const_iterator p=complex_ptns.begin();
p != complex_ptns.end();
++p )
{
const int &i = *p;
const compiled_binpat_t &ptn = ptns[i];
size_t vecsize = ptn.bytes.size();
size_t nbytes = qmin(rest, vecsize);
if ( !match_pattern(page+last_off-nbytes, ptn, vecsize-nbytes, nbytes) )
continue;
if ( vecsize <= rest )
{
*found_ea = page_ea + last_off - nbytes;
return true; // fits the page, a simple comparison is enough
}
// remember partial match
partmatch_t pm;
pm.match_ea = page_ea + last_off - vecsize;
pm.ptn_idx = i;
pm.ptn_off = nbytes;
pmatches.push_back(pm);
}
return false;
}
//--------------------------------------------------------------------------
// try to match simple patterns inside the page
// the partial match is processed as described above
bool match_simple_patterns(ea_t last_off)
{
const uchar *page_ptr = page + page_off;
for ( intvec_t::const_iterator q=simple_ptns.begin();
q != simple_ptns.end();
++q )
{
const int &i = *q;
size_t rest = last_off - page_off;
const bytevec_t &ptn_bytes = ptns[i].bytes;
size_t ptn_sz = ptn_bytes.size();
uchar ptn_ch = ptn_bytes[ptn_sz-1];
while ( rest > 0 )
{
const uchar *p = (uchar *)local_memrchr(page_ptr, ptn_ch, rest);
if ( p == NULL )
break;
rest = p + 1 - page_ptr;
size_t nbytes = qmin(rest, ptn_sz);
if ( memcmp(p + 1 - nbytes, &ptn_bytes[ptn_sz - nbytes], nbytes) == 0 )
{
ea_t matched_ea = page_ea + (p + 1 - page) - ptn_sz;
if ( ptn_sz <= rest )
{
*found_ea = matched_ea;
return true;
}
// remember partial match
partmatch_t pm;
pm.match_ea = matched_ea;
pm.ptn_idx = i;
pm.ptn_off = nbytes;
pmatches.push_back(pm);
}
rest -= 1;
}
}
return false;
}
//--------------------------------------------------------------------------
// try to finalize a partial match by matching the previous part of the
// long pattern against the end of the PAGE. patterns that are still
// too long for matching may produce new partial matches.
drc_t finalize_partial_match(partmatch_t &pm)
{
const compiled_binpat_t &ptn = ptns[pm.ptn_idx];
size_t vecsize = ptn.bytes.size();
size_t ptn_rest = vecsize - pm.ptn_off;
size_t nbytes = qmin(ptn_rest, PAGESZ - page_off);
if ( !match_pattern(page + PAGESZ - nbytes, ptn, ptn_rest - nbytes, nbytes) )
return DRC_FAILED;
if ( ptn_rest <= PAGESZ - page_off )
{
*found_ea = pm.match_ea;
return DRC_OK; // finalized the match
}
if ( page_off != 0 )
return DRC_FAILED;
// remember a new partial match
pm.ptn_off += PAGESZ;
return DRC_NONE;
}
};
#ifndef TEST
//--------------------------------------------------------------------------
// Note:
// The input search range can include the unreadable memory regions.
// For example, "[vvar]" on Linux.
// read_memory() returns 0 when trying to read from such region.
// These regions must be skipped.
drc_t idaapi debmod_t::dbg_bin_search(
ea_t *found_ea,
ea_t start_ea,
ea_t end_ea,
const compiled_binpat_vec_t &ptns,
int srch_flags,
qstring *errbuf)
{
static int forbidden = -1;
if ( forbidden == -1 )
forbidden = qgetenv("IDA_IDB_BIN_SEARCH", NULL);
if ( forbidden )
return DRC_NONE;
debdeb("dbg_bin_search %a..%a\n", start_ea, end_ea);
if ( start_ea >= end_ea || ptns.empty() || old_ranges.empty() )
return DRC_NONE;
//lint -esym(429,matcher) has not been freed
matcher_t *matcher = NULL;
matcher_janitor_t matcher_janitor(matcher);
bool search_backward = (srch_flags & BIN_SEARCH_BACKWARD) != 0;
if ( search_backward )
matcher = new backward_matcher_t(found_ea, this, ptns, srch_flags, errbuf);
else
matcher = new forward_matcher_t(found_ea, this, ptns, srch_flags, errbuf);
drc_t drc = matcher->walk_memory_ranges(start_ea, end_ea);
if ( drc != DRC_ERROR )
return drc; //-V773 without releasing the 'matcher' pointer
ea_t failed_ea = matcher->get_failed_address();
if ( failed_ea != BADADDR )
{
debdeb("dbg_bin_search failed to read memory at %a\n", failed_ea);
if ( errbuf != NULL && errbuf->empty() )
errbuf->sprnt("Failed to read memory at %a\n", failed_ea);
}
return DRC_ERROR;
}
#else // TEST
//--------------------------------------------------------------------------
drc_t binary_search(
ea_t *found_ea,
ea_t start_ea,
ea_t end_ea,
const compiled_binpat_vec_t &ptns,
int srch_flags,
qstring *errbuf)
{
matcher_t *matcher;
if ( (srch_flags & BIN_SEARCH_BACKWARD) != 0 )
matcher = new backward_matcher_t(found_ea, NULL, ptns, srch_flags, errbuf);
else
matcher = new forward_matcher_t(found_ea, NULL, ptns, srch_flags, errbuf);
drc_t drc = matcher->find(start_ea, end_ea);
delete matcher;
return drc;
}
//---------------------------------------------------------------------------
inline bool cmpbytes(
const uchar *ptr,
uchar b,
const uchar *pptr,
size_t ptnsize,
bool sense_case)
{
if ( sense_case )
return *ptr == b && memcmp(ptr+1, pptr, ptnsize) == 0; //lint !e670
if ( qtoupper(b) != qtoupper(*ptr) )
return false;
++ptr;
for ( int i=0; i < ptnsize; ++i, ++ptr, ++pptr )
{
if ( qtoupper(*ptr) != qtoupper(*pptr) )
return false;
}
return true;
}
//---------------------------------------------------------------------------
void *memmem(
const void *buf,
size_t bufsize,
const void *ptn,
size_t ptnsize,
bool sense_case)
{
if ( int(ptnsize) <= 0 || int(bufsize) < 0 || ptnsize > bufsize )
return NULL;
const uchar *ptr = (const uchar *)buf;
const uchar *const end = ptr + bufsize - ptnsize + 1;
const uchar *pptr = (const uchar *)ptn;
uchar b = *pptr++;
ptnsize--;
while ( ptr < end )
{
if ( cmpbytes(ptr, b, pptr, ptnsize, sense_case) )
return (void *)ptr;
++ptr;
}
return NULL;
}
//---------------------------------------------------------------------------
void *memmemr(
const void *buf,
size_t bufsize,
const void *ptn,
size_t ptnsize,
bool sense_case)
{
if ( int(ptnsize) <= 0 || int(bufsize) < 0 || ptnsize > bufsize )
return NULL;
const uchar *ptr = (const uchar *)buf + bufsize - ptnsize;
const uchar *const start = (const uchar *)buf;
const uchar *pptr = (const uchar *)ptn;
uchar b = *pptr++;
ptnsize--;
while ( start <= ptr )
{
if ( cmpbytes(ptr, b, pptr, ptnsize, sense_case) )
return (void *)ptr;
--ptr;
}
return NULL;
}
//--------------------------------------------------------------------------
drc_t simple_binary_search(
eavec_t *found_eas,
ea_t start_ea,
ea_t end_ea,
const compiled_binpat_vec_t &ptns,
int srch_flags,
qstring * /*errbuf*/)
{
if ( start_ea >= end_ea || start_ea > sizeof(memory) )
return DRC_FAILED;
bool sense_case = (srch_flags & BIN_SEARCH_CASE) != 0;
found_eas->clear();
bool backward = (srch_flags & BIN_SEARCH_BACKWARD) != 0;
for ( compiled_binpat_vec_t::const_iterator p=ptns.begin();
p != ptns.end();
++p )
{
const bytevec_t &vec = p->bytes;
uchar *start = memory + start_ea;
asize_t nbytes = qmin(sizeof(memory)-start_ea, end_ea-start_ea);
uchar *f = (uchar *)(backward
? memmemr(start, nbytes, vec.begin(), vec.size(), sense_case)
: memmem(start, nbytes, vec.begin(), vec.size(), sense_case));
if ( f == NULL )
continue;
ea_t idx = f - memory;
if ( idx >= end_ea )
continue;
found_eas->push_back(idx);
}
return found_eas->empty() ? DRC_FAILED : DRC_OK;
}
//--------------------------------------------------------------------------
static bool check(qstring *found1_s, const eavec_t &found1, ea_t found2)
{
bool ok = found1.empty() && found2 == BADADDR;
for ( int k=0; k < found1.size(); ++k )
{
if ( found1[k] == found2 )
ok = true;
if ( k > 0 )
found1_s->append(',');
found1_s->cat_sprnt("%a", found1[k]);
}
if ( found1_s->empty() )
found1_s->sprnt("%a", BADADDR);
return ok;
}
//--------------------------------------------------------------------------
int main(int argc, char *argv[])
{
bool sense_case = false;
int max_ptns = 3;
for ( int i=1; i < argc; ++i )
{
char argch = argv[i][0];
if ( argch == 'C' )
{
sense_case = true;
}
else if ( '0' < argch && argch <= '9' )
{
max_ptns = argch - '0';
}
}
msg("Test bin_search with %d pattern[s] and %s\n",
max_ptns,
sense_case ? "case sensitive" : "case ignored");
for ( int i=0; i < sizeof(memory); i++ )
memory[i] = i;//rand();
for ( int i=0; i < 1000000; i++ )
{
// prepare a pattern for searching
compiled_binpat_vec_t ptns;
int ptns_cnt = max_ptns == 1 ? 1 : (rand() % max_ptns) + 1;
ptns.resize(ptns_cnt);
qstring out;
for ( int c=0; c < ptns.size(); c++ )
{
size_t off = rand() % sizeof(memory);
size_t len = (rand() % sizeof(memory)/20) + 1;
if ( (rand() % 50) == 0 )
len += 8;
compiled_binpat_t &pat = ptns[c];
pat.bytes.resize(len, 0xFF);
size_t copyable = qmin(sizeof(memory)-off, len);
memcpy(pat.bytes.begin(), &memory[off], copyable);
if ( c > 0 )
out.append(",");
out.cat_sprnt("%X:%X", int(off), int(len));
// if some rare cases make the pattern possibly insearchable
if ( (rand() % 50) == 0 )
{
pat.bytes[0] = 0xAA;
out.append("-");
}
}
ea_t start_ea = rand() % sizeof(memory);
ea_t end_ea = start_ea + (rand() % sizeof(memory));
if ( end_ea > sizeof(memory) )
end_ea = sizeof(memory); // no need to test out of memory
int flags = sense_case ? BIN_SEARCH_CASE : BIN_SEARCH_NOCASE;
eavec_t found1;
simple_binary_search(&found1, start_ea, end_ea, ptns, flags|BIN_SEARCH_FORWARD, NULL);
ea_t found2 = BADADDR;
binary_search(&found2, start_ea, end_ea, ptns, flags|BIN_SEARCH_FORWARD, NULL);
qstring found1_s;
bool ok = check(&found1_s, found1, found2);
msg("%3d find (%s) in (%a..%a) => %s %a\n", i, out.c_str(), start_ea, end_ea, found1_s.c_str(), found2);
if ( !ok )
{
msg("FAILED!\n");
return 1;
}
found1.clear();
simple_binary_search(&found1, start_ea, end_ea, ptns, flags|BIN_SEARCH_BACKWARD, NULL);
found2 = BADADDR;
binary_search(&found2, start_ea, end_ea, ptns, flags|BIN_SEARCH_BACKWARD, NULL);
found1_s.qclear();
ok = check(&found1_s, found1, found2);
msg("%3d findr(%s) in (%a..%a) => %s %a\n", i, out.c_str(), start_ea, end_ea, found1_s.c_str(), found2);
if ( !ok )
{
msg("FAILED!\n");
return 1;
}
}
msg("OK\n");
return 0;
}
#endif // TEST

View File

@@ -0,0 +1,34 @@
/*
* Interactive disassembler (IDA).
* ALL RIGHTS RESERVED.
* Copyright (c) 1990-2020 Hex-Rays
*
*
* This file defines the Bochs Debugger module extension functions.
* Use debugger_t->get_debmod_extensions() to retrieve this structure.
*
*/
#ifndef __BOCHSEXT__
#define __BOCHSEXT__
#pragma pack(push, 1)
#define BOCHSEXT_VER 1
struct bochsext_t
{
// the structure version
uint32 version;
// Sends an arbitrary command to Bochs internal debugger
// cmd - command to send
// out - pointer to qstring that will hold the output of the command
// Returns: true if ok; false if failed to send command to bochs or receive
// a reply
bool (idaapi *send_command)(const char *cmd, qstring *out);
};
#pragma pack(pop)
#endif

View File

@@ -0,0 +1,62 @@
/*
* Interactive disassembler (IDA).
* ALL RIGHTS RESERVED.
* Copyright (c) 1990-2020 Hex-Rays
*
*
* This file defines the functions prototypes that are exported by bochsys.dll
*
*
*/
#ifndef __BOCHSYS_DLL__
#define __BOCHSYS_DLL__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define BX_CALLCONV WINAPI
typedef wchar_t wchar16_t;
//CASSERT(sizeof(wchar16_t) == 2);
//--------------------------------------------------------------------------
// These functions are similar to MS Windows functions. Please refer
// to the SDK documentation for more information on how to use them.
extern FARPROC WINAPI BxGetProcAddress(HMODULE hMod, LPCSTR ProcName);
extern HMODULE WINAPI BxGetModuleHandleA(LPCSTR ModuleFileName);
extern DWORD WINAPI BxGetModuleFileNameA(HINSTANCE hModule, LPCSTR lpFilename, DWORD nSize);
extern DWORD WINAPI BxGetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize);
extern HMODULE WINAPI BxLoadLibraryA(LPCTSTR lpFileName);
extern LPVOID WINAPI BxVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
extern BOOL WINAPI BxVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
extern DWORD WINAPI BxExitProcess(DWORD);
extern DWORD WINAPI BxGetTickCount(VOID);
extern BOOL WINAPI BxVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
extern DWORD WINAPI BxWin32SetLastError(DWORD ErrorCode);
extern DWORD WINAPI BxWin32GetLastError(VOID);
extern LPCSTR WINAPI BxWin32GetCommandLineA(VOID);
extern LPWSTR WINAPI BxWin32GetCommandLineW(VOID);
extern LPCSTR WINAPI BxWin32GetEnvironmentStringsA(VOID);
extern LPWSTR WINAPI BxWin32GetEnvironmentStringsW(VOID);
extern LPVOID WINAPI BxWin32TlsGetValue(DWORD dwTlsIndex);
extern BOOL WINAPI BxWin32TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue);
extern BOOL WINAPI BxWin32TlsFree(DWORD dwTlsIndex);
extern DWORD WINAPI BxWin32TlsAlloc(VOID);
extern DWORD WINAPI BxWin32FlsAlloc(VOID);
extern char * WINAPI BxStrCpyA(char *Dst, char *Src);
extern wchar16_t * WINAPI BxStrCpyW(wchar16_t *Dst, wchar16_t *Src);
extern char * WINAPI BxStrCatA(char *Dst, char *Src);
extern wchar16_t * WINAPI BxStrCatW(wchar16_t *Dst, wchar16_t *Src);
//--------------------------------------------------------------------------
// Installs an exception handler. Only one exception handler
// can be installed at one time. You need to uninstall one
// before reinstalling another.
// These two functions will return non-zero on success.
typedef DWORD (*PEXCEPTION_HANDLER)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD *, PCONTEXT,struct _EXCEPTION_REGISTRATION_RECORD **);
extern DWORD WINAPI BxInstallSEH(PEXCEPTION_HANDLER Handler);
extern DWORD WINAPI BxUninstallSEH();
#endif

View File

@@ -0,0 +1,271 @@
// This file contains bochs startup and exit procedures bochs_startup() and bochs_exit()
// The former is called when the process starts
// The latter is called when the process is about to exit
// Both functions cause IDA debugger to suspend if they return a non zero value
// This section declares which DLLs will be available:
// * Use the "stub" to mark a dll for stubbing
// * Use the "load" to mark a dll to be loaded as is
// The "load" keyword has an additional attributes called "R0UserEntry"
// This attribute is used to designate an exported function that will be called from ring0
// Such a mechanism is useful to extend bochsys kernel or even replace it after it is loaded
// One simple application is to modify the IDT and add R3 callable interrupts into your kernel
// Only lines containing three forward slashes ("/") are processed:
/// stub ntdll.dll
/// stub kernel32.dll
/// stub user32.dll
/// stub shell32.dll
/// stub shlwapi.dll
/// stub urlmon.dll
/// stub advapi32.dll
/// stub mswsock.dll
/// stub wininet.dll
/// stub msvcrt.dll
/// stub gdi32.dll
/// stub ole32.dll
/// stub wsock32.dll
/// stub ws2_32.dll
// Define our own environment variables.
// (add triple slashes to enable)
// env path=c:\games\bin;d:\bin\asdf\
// env userprofile=c:\games\
// Define your dependency mappings
// (add triple slashes to enable the following lines)
// map /home/guest/sys_dlls/user32.dll=d:\winnt\system32\user32.dll
// map /home/guest/sys_dlls/shell32.dll=d:\winnt\system32\shell32.dll
// map /home/guest/sys_dlls/kernel32.dll=d:\winnt\system32\kernel32.dll
// map /home/guest/sys_dlls/shlwapi.dll=d:\winnt\system32\shlwapi.dll
// map /home/guest/sys_dlls/urlmon.dll=d:\winnt\system32\urlmon.dll
// map /home/guest/sys_dlls/mswsock.dll=d:\winnt\system32\mswsock.dll
// map /home/guest/sys_dlls/wininet.dll=d:\winnt\system32\wininet.dll
// map /home/guest/sys_dlls/msvcrt.dll=d:\winnt\system32\msvcrt.dll
// map /home/guest/sys_dlls/gdi32.dll=d:\winnt\system32\gdi32.dll
// map /home/guest/sys_dlls/ntdll.dll=d:\winnt\system32\ntdll.dll
// map /home/guest/sys_dlls/advapi32.dll=d:\winnt\system32\advapi32.dll
// Define additional DLL path
// (add triple slashes to enable the following lines)
// path /home/guest/sys_dlls/=c:\winnt\system32\
// Bochs debugger plugin also allows you to specify the DLL path through the environment variable IDABXPATHMAP
// (It is possible to specify more than one key/value pair by separating them with a semi-colon)
// For example:
// $ export IDABXPATHMAP="/home/guest/sys_dlls/=c:/winnt/system32/;/home/user2/other_dlls/=c:/program files/common files/3rd party/"
// Similarly, one can specify the environment variables through the environment variable IDABXENVMAP
// (it is possible to specify more than one key/value pair by separating them with a "++")
// For example:
// $ export IDABXENVMAP="TMP=c:/Users/Guest/Temp++SystemDrive=C:++windir=c:/windows/"
//
// Please note that the forward slashes "/" in the value part of the key/value pair will always be replaced with a backslash
//
// The following are oneshot options. Once set they cannot be unset.
// To define them simply preceed the option name with triple slashes.
// - nosearchpath: Disables SearchPath() use for finding DLLs (this option is applicable on MS Windows only).
// By turning this option, Bochs plugin will try to load DLLs from the current directory.
// It useful for loading certain (old or new) versions of system DLLs instead of the ones currently installed
// on the system.
// - noactivationcontext: Disables the use of "Activation Context" (this option is applicable on MS Windows only).
//
//
// For loading drivers, you may uncomment the following stub definition(s):
//
// stub ntoskrnl.exe
// For example: to load a dll as is: load mydll.dll
// For example: to load a dll as is and specify a user R0 entry: load mydll.dll R0UserEntry=MyExportedFunc
#include <idc.idc>
//--------------------------------------------------------------------------
// IDC scripts that will be available during the debugging session
// MS Windows related functions
// ------------------------------
// BochsVirtXXXX functions allocate/free virtual memory in the emulated session.
// The "size" parameter is always rounded to a page.
//
//
// Allocate virtual memory
// This function emulates the VirtualAlloc function from MS Windows
// addr - the preferred address for the allocation. Zero means no preference
// size - size of the block to allocate
// writable - should be allocated memory be wrtiable?
// Currently only read/write page protections are supported
// Returns: the address of the allocated block or zero
//
// long BochsVirtAlloc(long addr, long size, bool writable);
//
//
// Change protection of memory page
// This function emulates the VirtualProtect function from MS Windows
// addr - the desired address to change protection.
// size - size of the block
// attr - the new page attribute:
// 0 = Read only
// 1 = Read/Write
// Returns: the old protection value or -1 on failure
//
// long BochsVirtProtect(long addr, long size, long attr);
//
//
// Free virtual memory
// This function emulates the VirtualFree function from MS Windows
// addr - the address of previously allocated memory block
// size - the size of the block. If zero, then the entire block at addr
// will be freed.
// Returns: success
//
// bool BochsVirtFree(long addr, long size);
//
//
// Returns the base address of a given module name
// module_name - The name of the module.
// The name can be full path or filename with extension, or simply filename without extension
// Returns: zero if it fails
//
// long BochsGetModuleHandle(string module_name);
//
//
// Returns a procedure's address
// This function calls the internal GetProcAddress to resolve function addresses.
// hmod - the module handle
// procname - name of the procedure inside the module
// Returns: the zero if procedure not found, otherwise the address
//
// long BochsGetProcAddress(long hmod, string procname);
//
//
// Returns the module name given its base address
// module_handle: the base address of a given module
// Returns: empty string if module was not found
//
// string BochsGetModuleFileName(long module_handle)
//
//
// Returns the command line value passed to the application
//
// string BochsGetCommandLine()
//
//
// Set last error code
// This function emulates the SetLastError function from MS Windows.
// It writes the specified code to TIB.
// error_code - new error code to set
// Returns: success
//
// success BochsWin32SetLastError(long error_num);
//
//
// Other functions:
// -------------------
//
//
// Sends arbitrary commands to the internal debugger of BOCHS. The output is returned as a string.
// This is useful for example to send some commands to BOCHS that are not exposed via the GUI of IDA.
// command: the command you want to send
// Returns: output string or empty string if it failed
//
// string send_dbg_command(string command)
//
//
// Retrieves the parameter value passed to an IDC script that is implementing a given API.
// This same function can be implemented with this expression: #define BX_GETPARAM(n) get_wide_dword(esp+4*(n+1))
// arg_num: the argument number (starting by one)
// Returns: the value or zero in case it fails
//
// string BochsGetParam(long arg_num)
//
//
// Calls a function inside Bochs
// This function can call functions inside Bochs. Very useful if you want to call
// functions in the user's code. The arguments are pushed from right to left.
// func_ptr - The address of the function to be called
// argN - a set of dwords that contain the arguments.
// Arguments can be numbers or pointers
// Returns: success
//
// long BochsCall(long func_ptr, arg1, arg2, ...);
//
//
// These functions will return the total physical memory amount and the remaining free
// memory in bytes.
// Returns: memory size in bytes
//
// long BochsGetFreeMem()
// long BochsGetMaxMem()
//
// ----------------------------------------------------------------------------
static BochsPatchDbgDword(ea, dv)
{
auto i;
for (i=0;i<4;i++)
{
patch_dbg_byte(ea, dv & 0xFF);
ea = ea + 1;
dv = dv >> 8;
}
}
// ----------------------------------------------------------------------------
// Utility function that can be used as a conditional breakpoint condition
// in order to skip to the next instruction w/o suspending IDA
static bochs_skipnext()
{
Eip = next_head(eip, BADADDR);
return 0;
}
// ----------------------------------------------------------------------------
// Utility function that can be used as a conditional breakpoint condition
// in order to execute the contents of the comments at the bp location
static bochs_execidc_comments()
{
exec_idc(Comment(eip));
return 0;
}
// ----------------------------------------------------------------------------
// Utility function used to dump registers. The output can be used as a comment
// with the bochs_execidc_comments() bp condition
static bochs_dump_registers()
{
msg("eax=0x%x;ebx=0x%x;ecx=0x%x;edx=0x%x;esi=0x%x;edi=0x%x;ebp=0x%x;", eax, ebx, ecx, edx, esi, edi, ebp);
}
// ----------------------------------------------------------------------------
static bochs_startup()
{
msg("Bochs debugger has been initialized.\n");
return 0;
}
// ----------------------------------------------------------------------------
static bochs_exit()
{
msg("Bochs debugger has been terminated.\n");
return 0;
}

View File

@@ -0,0 +1,2 @@
///func=MessageBoxA entry=bxtest.MyMessageBox

View File

@@ -0,0 +1,89 @@
#include "bochsys.h"
#include <windows.h>
//--------------------------------------------------------------------------
// dummy entry point so that linker does not use entrypoints from CRT
DWORD WINAPI Entry(DWORD a, DWORD b, DWORD c)
{
return 0;
}
//--------------------------------------------------------------------------
// This function will be called by bochsys.dll from R0 before switching to R3
// This is even called before TLS callbacks
void WINAPI MyR0Entry(VOID)
{
__asm
{
nop
mov dx, 0378h
in eax, dx
nop
nop
}
}
//--------------------------------------------------------------------------
DWORD MyHandler(
PEXCEPTION_RECORD rec,
struct _EXCEPTION_REGISTRATION_RECORD *reg,
PCONTEXT ctx,
struct _EXCEPTION_REGISTRATION_RECORD **reg2)
{
ctx->Eip += 2;
return ExceptionContinueExecution;
}
//--------------------------------------------------------------------------
void BuggyFunction()
{
BxInstallSEH(MyHandler);
__asm
{
xor eax, eax
mov eax, [eax]
}
BxUninstallSEH();
}
//--------------------------------------------------------------------------
// In this function, BxXXXXXX functions are used from the bochsys library
int __stdcall MyMessageBox(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType)
{
char *p;
int i;
// Allocate memory
p = BxVirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_READWRITE);
// Fill the memory
for (i=1;i<=0x1000;i++)
*p++ = i & 0xFF;
// Resolve an entry and call it
(VOID (__stdcall *)(int, int)) BxGetProcAddress(BxLoadLibraryA("kernel32.dll"), "Beep")(5, 1);
// Call a function that might cause an exception
BuggyFunction();
return 0;
}
//--------------------------------------------------------------------------
// In this function we import from user32 and kernel32
// (because VirtualAlloc->BxVirtualAlloc and MessageBoxA->bxtest.MyMessageBox are redirected and implemented)
int __stdcall MyRoutine(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType)
{
VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_READWRITE);
MessageBoxA(0, "hey", "info", MB_OK);
return 0;
}

View File

@@ -0,0 +1,4 @@
EXPORTS
MyMessageBox
MyRoutine
MyR0Entry

Binary file not shown.

View File

@@ -0,0 +1,11 @@
@echo off
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\cl.exe" -c /Zl /Gd /Tc bxtest.c "/IC:/Program Files (x86)/Windows Kits/8.1/Include/um" "/IC:/Program Files (x86)/Windows Kits/8.1/Include/shared" "/IC:/PROGRA~2/WI3CF2~1/10/Include/10.0.10150.0/ucrt" /I"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include"
if errorlevel 1 goto end
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\link.exe" bxtest.obj bochsys.lib kernel32.lib user32.lib /OUT:bxtest.dll /ENTRY:Entry /def:bxtest.def /DRIVER /SAFESEH:NO /NODEFAULTLIB /SUBSYSTEM:WINDOWS /LIBPATH:"C:\Program Files\Microsoft Visual Studio 14.0\VC\Lib" /LIBPATH:"C:/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x86"
if errorlevel 1 goto end
if exist bxtest.obj del bxtest.obj
if exist bxtest.exp del bxtest.exp
if exist bxtest.lib del bxtest.lib
:end

View File

@@ -0,0 +1,90 @@
Custom DLLs for emulated MS Windows environment
-----------------------------------------------
This directory contains files that demonstrate how to build a custom DLL
for the PE loader of the Bochs debugger.
compile.bat shows how to build a custom DLL with the MS compiler/linker.
The general rule is not to link with runtime libraries, but linking with
import libraries is ok.
"bxtest.c" demonstrates how to call functions in bochsys.dll.
"bochsys.h" has the list of functions that can be called from custom DLLs.
"bochsys.lib" is the corresponding import library
Custom DLLs must be mentioned in plugins\bochs\startup.idc.
For that please add a line like this:
/// load bxtest.dll
This will cause the DLL to be present in the memory space of the debugged process.
For the custom DLL to be useful, its exported functions should be connected
to API function names. For example, the following line redirects MessageBoxA
to bxtest.MyMessageBox:
/// func=MessageBoxA entry=bxtest.MyMessageBox
The exact format of the startup.idc file is explained in its header.
On the other hand, it is also possible to write a custom DLL that replaces system
DLLs like kernel32.dll or user32.dll.
The "load" command has an additional parameter "R0UserEntry=MyR0Entry" used as:
///load bxtest.dll R0UserEntry=MyR0Entry
Which means that bxtest.dll should be loaded into the process memory and
that this DLL has an exported entry that should be called by bochsys from ring0.
Such a facility is ideal if you're looking to replace or enhance bochsys's kernel.
To test how MessageBoxA is redirected to MyMessageBox, please follow these
steps:
- compile and link bxtest.dll with compile.bat
(we provide ready-to-use bxtest.dll for your convenience, so you
skip this step)
- add two lines mentioned above to startup.idc and api_user32.idc respectively
- load test.pe into IDA and select Bochs debugger
- run it and single step into the MessageBoxA function
With any questions, please contact us at support@hex-rays.com
Bochs plugin debugger extensions
-----------------------------------
Bochs extensions allow for accessing extended debugger functionality.
To get and use the extensions, query the currently loaded debugger using
get_debmod_extensions(). Usually it returns a pointer to a structure with
pointers to functions. Please follow this example:
#include "bochsext.h"
void idaapi run(int)
{
if ( dbg == NULL )
{
msg("dbg == NULL\n");
return;
}
const bochsext_t *ext = (const bochsext_t *)dbg->get_debmod_extensions();
if ( ext == NULL )
{
msg("no debugger extensions!\n");
return;
}
// dump 10 bytes from physical memory at 0x0
qstring out;
if ( !ext->send_command("xp /10mb 0x0\r\n", &out) )
{
msg("failed to send command!\n");
return;
}
msg("->result=%s\n", out.c_str());
}

View File

@@ -0,0 +1,36 @@
; #########################################################################
.386
.model flat, stdcall
option casemap :none ; case sensitive
; #########################################################################
include d:\masm32\include\windows.inc
include d:\masm32\include\user32.inc
include d:\masm32\include\kernel32.inc
includelib d:\masm32\lib\user32.lib
includelib d:\masm32\lib\kernel32.lib
; #########################################################################
; --------------------------------------------------------
.data
szDlgTitle db "Minimum MASM",0
szMsg db " --- Assembler Pure and Simple --- ",0
.code
start:
; --------------------------------------------------------
; script
push MB_OK
push offset szDlgTitle
push offset szMsg
push 0
call MessageBox
; --------------------------------------------------------
; idacall
push -2
call ExitProcess
end start

Binary file not shown.

View File

@@ -0,0 +1,857 @@
//
// This file is included from other files, do not directly compile it.
// It contains the debugger_t structure definition and a few other helper functions
//
#include <loader.hpp>
#include <segregs.hpp>
#include <network.hpp>
bool plugin_inited;
bool debugger_inited;
#define IS_GDB_DEBUGGER (DEBUGGER_ID == DEBUGGER_ID_GDB_USER || DEBUGGER_ID == DEBUGGER_ID_ARM_IPHONE_USER || DEBUGGER_ID == DEBUGGER_ID_XNU_USER)
#if TARGET_PROCESSOR == PLFM_386
#define REGISTERS x86_registers
#define REGISTERS_SIZE qnumber(x86_registers)
#define REGISTER_CLASSES x86_register_classes
#define REGISTER_CLASSES_DEFAULT X86_RC_GENERAL
#define READ_REGISTERS x86_read_registers
#define WRITE_REGISTER x86_write_register
#if !IS_GDB_DEBUGGER
#define is_valid_bpt is_x86_valid_bpt
#endif
#define BPT_CODE X86_BPT_CODE
#define BPT_CODE_SIZE X86_BPT_SIZE
#elif TARGET_PROCESSOR == PLFM_ARM
#define REGISTERS arm_registers
#define REGISTERS_SIZE qnumber(arm_registers)
#define REGISTER_CLASSES arm_register_classes
#define REGISTER_CLASSES_DEFAULT ARM_RC_GENERAL
#define READ_REGISTERS s_read_registers
#define WRITE_REGISTER s_write_register
#if !IS_GDB_DEBUGGER
#define is_valid_bpt is_arm_valid_bpt
#else
#define is_valid_bpt gdb_valid_bpt
#endif
#define BPT_CODE ARM_BPT_CODE
#define BPT_CODE_SIZE ARM_BPT_SIZE
#elif TARGET_PROCESSOR == PLFM_DALVIK
#define BPT_CODE { 0 }
#define BPT_CODE_SIZE 0
#define READ_REGISTERS s_read_registers
#define WRITE_REGISTER s_write_register
#define is_valid_bpt is_dalvik_valid_bpt
#elif IS_GDB_DEBUGGER
#define REGISTERS NULL
#define REGISTERS_SIZE 0
#define REGISTER_CLASSES NULL
#define REGISTER_CLASSES_DEFAULT 0
#define READ_REGISTERS simple_read_registers
#define WRITE_REGISTER simple_write_register
#define is_valid_bpt gdb_valid_bpt
#define BPT_CODE { 0 }
#define BPT_CODE_SIZE 0
#else
#error This processor is not supported yet
#endif
static const uchar bpt_code[] = BPT_CODE;
//--------------------------------------------------------------------------
int idaapi is_ok_bpt(bpttype_t type, ea_t ea, int len)
{
int ret = is_valid_bpt(type, ea, len);
if ( ret != BPT_OK )
return ret;
else
return g_dbgmod.dbg_is_ok_bpt(type, ea, len);
}
//--------------------------------------------------------------------------
// For ARM, we have to set the low bit of the address to 1 for thumb mode
#if DEBUGGER_ID == DEBUGGER_ID_ARM_LINUX_USER
static drc_t idaapi arm_update_bpts(
int *nbpts,
update_bpt_info_t *bpts,
int nadd,
int ndel,
qstring *errbuf)
{
// This function is called from debthread, but to use get_sreg() we must
// switch to the mainthread
struct ida_local arm_bptea_fixer_t : public exec_request_t
{
update_bpt_info_t *bpts;
update_bpt_info_t *e;
qvector<ea_t *> thumb_mode;
virtual int idaapi execute(void) override
{
for ( update_bpt_info_t *b=bpts; b != e; b++ )
{
if ( b->type == BPT_SOFT && get_sreg(b->ea, ARM_T) == 1 )
{
b->ea++; // odd address means that thumb bpt must be set
thumb_mode.push_back(&b->ea);
}
}
return 0;
}
arm_bptea_fixer_t(update_bpt_info_t *p1, update_bpt_info_t *p2)
: bpts(p1), e(p2) {}
};
arm_bptea_fixer_t abf(bpts, bpts+nadd);
execute_sync(abf, MFF_READ);
drc_t drc = s_update_bpts(nbpts, bpts, nadd, ndel, errbuf);
// reset the odd bit because the addresses are required by the caller
for ( int i=0; i < abf.thumb_mode.size(); i++ )
(*abf.thumb_mode[i])--;
return drc;
}
#define s_update_bpts arm_update_bpts
#endif
//--------------------------------------------------------------------------
static drc_t idaapi update_bpts(
int *nbpts,
update_bpt_info_t *bpts,
int nadd,
int ndel,
qstring *errbuf)
{
bool valid_bpt_exists = false;
update_bpt_info_t *e = bpts + nadd;
for ( update_bpt_info_t *b=bpts; b != e; b++ )
{
if ( b->code == BPT_SKIP )
continue;
b->code = is_valid_bpt(b->type, b->ea, b->size);
if ( b->code == BPT_OK )
valid_bpt_exists = true;
}
if ( !valid_bpt_exists && ndel == 0 )
{
if ( nbpts != NULL )
*nbpts = 0;
return DRC_OK; // none of bpts is writable
}
drc_t drc = s_update_bpts(nbpts, bpts, nadd, ndel, errbuf);
return drc;
}
//--------------------------------------------------------------------------
#ifndef REMOTE_DEBUGGER
// another copy of this function (for remote debugging) is defined in dbg_rpc_handler.cpp
int send_ioctl(
void *,
int fn,
const void *buf,
size_t size,
void **poutbuf,
ssize_t *poutsize)
{
return g_dbgmod.handle_ioctl(fn, buf, size, poutbuf, poutsize);
}
#endif
//--------------------------------------------------------------------------
THREAD_SAFE int debmod_t::send_debug_names_to_ida(
ea_t *addrs,
const char *const *names,
int qty)
{
return ::send_debug_names_to_ida(addrs, names, qty);
}
//---------------------------------------------------------------------------
THREAD_SAFE int send_debug_names_to_ida(
ea_t *addrs,
const char *const *names,
int qty)
{
struct debug_name_handler_t : public exec_request_t
{
ea_t *addrs;
const char *const *names;
int qty;
debug_name_handler_t(ea_t *_addrs, const char *const *_names, int _qty)
: addrs(_addrs), names(_names), qty(_qty) {}
int idaapi execute(void) override
{
set_arm_thumb_modes(addrs, qty);
return set_debug_names(addrs, names, qty);
}
};
debug_name_handler_t dnh(addrs, names, qty);
return execute_sync(dnh, MFF_WRITE);
}
//--------------------------------------------------------------------------
THREAD_SAFE int debmod_t::send_debug_event_to_ida(
const debug_event_t *ev,
int rqflags)
{
return ::send_debug_event_to_ida(ev, rqflags);
}
//---------------------------------------------------------------------------
THREAD_SAFE int send_debug_event_to_ida(
const debug_event_t *ev,
int rqflags)
{
return handle_debug_event(ev, rqflags);
}
//--------------------------------------------------------------------------
THREAD_SAFE int import_dll(const import_request_t &req)
{
struct dll_importer_t : public exec_request_t
{
const import_request_t &req;
dll_importer_t(const import_request_t &_req) : req(_req) {}
int idaapi execute(void) override
{
return g_dbgmod.import_dll(req) ? 0 : 1;
}
};
dll_importer_t di(req);
return execute_sync(di, MFF_WRITE);
}
//--------------------------------------------------------------------------
#if TARGET_PROCESSOR != PLFM_ARM
void set_arm_thumb_modes(ea_t * /*addrs*/, int /*qty*/)
{
}
#endif
//--------------------------------------------------------------------------
// installs or uninstalls debugger specific idc functions
bool add_idc_funcs(const ext_idcfunc_t efuncs[], size_t nfuncs, bool reg)
{
if ( reg )
{
for ( int i=0; i < nfuncs; i++ )
if ( !add_idc_func(efuncs[i]) )
return false;
}
else
{
for ( int i=0; i < nfuncs; i++ )
if ( !del_idc_func(efuncs[i].name) )
return false;
}
return true;
}
//--------------------------------------------------------------------------
static drc_t init_debugger(
const char *hostname,
int port_num,
const char *password,
qstring *errbuf)
{
g_dbgmod.dbg_set_debugging((debug & IDA_DEBUG_DEBUGGER) != 0);
if ( !s_open_remote(hostname, port_num, password, errbuf) )
return DRC_FAILED;
uint32_t flags2 = 0;
drc_t drc = s_init(&flags2, errbuf);
if ( drc != DRC_OK )
{
s_close_remote();
return drc;
}
debugger.flags2 |= flags2;
#if defined(REMOTE_DEBUGGER) && !defined(NO_OPEN_FILE)
setflag(debugger.flags2, DBG_HAS_OPEN_FILE, true);
#endif
#ifdef HAVE_UPDATE_CALL_STACK
setflag(debugger.flags2, DBG_HAS_UPDATE_CALL_STACK, true);
#endif
#ifdef HAVE_APPCALL
setflag(debugger.flags2, DBG_HAS_APPCALL, true);
#endif
#ifdef HAVE_MAP_ADDRESS
setflag(debugger.flags2, DBG_HAS_MAP_ADDRESS, true);
#endif
debugger_inited = true;
processor_specific_init();
register_idc_funcs(true);
init_dbg_idcfuncs(true);
#if DEBUGGER_ID == DEBUGGER_ID_X86_IA32_WIN32_USER || DEBUGGER_ID == DEBUGGER_ID_X86_IA32_BOCHS
install_x86seh_menu();
#endif
return DRC_OK;
}
//--------------------------------------------------------------------------
static drc_t term_debugger(void)
{
if ( debugger_inited )
{
debugger_inited = false;
#if DEBUGGER_ID == DEBUGGER_ID_X86_IA32_WIN32_USER || DEBUGGER_ID == DEBUGGER_ID_X86_IA32_BOCHS
remove_x86seh_menu();
#endif
init_dbg_idcfuncs(false);
register_idc_funcs(false);
processor_specific_term();
g_dbgmod.dbg_term();
return s_close_remote();
}
return DRC_FAILED;
}
//--------------------------------------------------------------------------
static ssize_t idaapi idd_notify(void *, int msgid, va_list va)
{
int retcode = DRC_NONE;
qstring *errbuf;
switch ( msgid )
{
case debugger_t::ev_init_debugger:
{
const char *hostname = va_arg(va, const char *);
int portnum = va_arg(va, int);
const char *password = va_arg(va, const char *);
errbuf = va_arg(va, qstring *);
QASSERT(1522, errbuf != NULL);
retcode = init_debugger(hostname, portnum, password, errbuf);
}
break;
case debugger_t::ev_term_debugger:
retcode = term_debugger();
break;
case debugger_t::ev_get_processes:
{
procinfo_vec_t *procs = va_arg(va, procinfo_vec_t *);
errbuf = va_arg(va, qstring *);
retcode = g_dbgmod.dbg_get_processes(procs, errbuf);
}
break;
case debugger_t::ev_start_process:
{
const char *path = va_arg(va, const char *);
const char *args = va_arg(va, const char *);
const char *startdir = va_arg(va, const char *);
uint32 dbg_proc_flags = va_arg(va, uint32);
const char *input_path = va_arg(va, const char *);
uint32 input_file_crc32 = va_arg(va, uint32);
errbuf = va_arg(va, qstring *);
retcode = s_start_process(path,
args,
startdir,
dbg_proc_flags,
input_path,
input_file_crc32,
errbuf);
}
break;
case debugger_t::ev_attach_process:
{
pid_t pid = va_argi(va, pid_t);
int event_id = va_arg(va, int);
uint32 dbg_proc_flags = va_arg(va, uint32);
errbuf = va_arg(va, qstring *);
retcode = s_attach_process(pid, event_id, dbg_proc_flags, errbuf);
}
break;
case debugger_t::ev_detach_process:
retcode = g_dbgmod.dbg_detach_process();
break;
case debugger_t::ev_get_debapp_attrs:
{
debapp_attrs_t *out_pattrs = va_arg(va, debapp_attrs_t *);
g_dbgmod.dbg_get_debapp_attrs(out_pattrs);
retcode = DRC_OK;
}
break;
case debugger_t::ev_rebase_if_required_to:
{
ea_t new_base = va_arg(va, ea_t);
rebase_if_required_to(new_base);
retcode = DRC_OK;
}
break;
case debugger_t::ev_request_pause:
errbuf = va_arg(va, qstring *);
retcode = g_dbgmod.dbg_prepare_to_pause_process(errbuf);
break;
case debugger_t::ev_exit_process:
errbuf = va_arg(va, qstring *);
retcode = g_dbgmod.dbg_exit_process(errbuf);
break;
case debugger_t::ev_get_debug_event:
{
gdecode_t *code = va_arg(va, gdecode_t *);
debug_event_t *event = va_arg(va, debug_event_t *);
int timeout_ms = va_arg(va, int);
*code = g_dbgmod.dbg_get_debug_event(event, timeout_ms);
retcode = DRC_OK;
}
break;
case debugger_t::ev_resume:
{
debug_event_t *event = va_arg(va, debug_event_t *);
retcode = g_dbgmod.dbg_continue_after_event(event);
}
break;
case debugger_t::ev_set_exception_info:
{
exception_info_t *info = va_arg(va, exception_info_t *);
int qty = va_arg(va, int);
g_dbgmod.dbg_set_exception_info(info, qty);
retcode = DRC_OK;
}
break;
case debugger_t::ev_suspended:
{
bool dlls_added = va_argi(va, bool);
thread_name_vec_t *thr_names = va_arg(va, thread_name_vec_t *);
s_stopped_at_debug_event(thr_names, dlls_added);
retcode = DRC_OK;
}
break;
case debugger_t::ev_thread_suspend:
{
thid_t tid = va_argi(va, thid_t);
retcode = g_dbgmod.dbg_thread_suspend(tid);
}
break;
case debugger_t::ev_thread_continue:
{
thid_t tid = va_argi(va, thid_t);
retcode = g_dbgmod.dbg_thread_continue(tid);
}
break;
case debugger_t::ev_set_resume_mode:
{
thid_t tid = va_argi(va, thid_t);
resume_mode_t resmod = va_argi(va, resume_mode_t);
retcode = g_dbgmod.dbg_set_resume_mode(tid, resmod);
}
break;
case debugger_t::ev_read_registers:
{
thid_t tid = va_argi(va, thid_t);
int clsmask = va_arg(va, int);
regval_t *values = va_arg(va, regval_t *);
errbuf = va_arg(va, qstring *);
retcode = READ_REGISTERS(tid, clsmask, values, errbuf);
}
break;
case debugger_t::ev_write_register:
{
thid_t tid = va_argi(va, thid_t);
int regidx = va_arg(va, int);
const regval_t *value = va_arg(va, const regval_t *);
errbuf = va_arg(va, qstring *);
retcode = WRITE_REGISTER(tid, regidx, value, errbuf);
}
break;
case debugger_t::ev_thread_get_sreg_base:
{
ea_t *answer = va_arg(va, ea_t *);
thid_t tid = va_argi(va, thid_t);
int sreg_value = va_arg(va, int);
errbuf = va_arg(va, qstring *);
retcode = g_dbgmod.dbg_thread_get_sreg_base(answer, tid, sreg_value, errbuf);
}
break;
case debugger_t::ev_get_memory_info:
{
meminfo_vec_t *ranges = va_arg(va, meminfo_vec_t *);
errbuf = va_arg(va, qstring *);
retcode = g_dbgmod.dbg_get_memory_info(*ranges, errbuf);
}
break;
case debugger_t::ev_read_memory:
{
size_t *nbytes = va_arg(va, size_t *);
ea_t ea = va_arg(va, ea_t);
void *buffer = va_arg(va, void *);
size_t size = va_arg(va, size_t);
errbuf = va_arg(va, qstring *);
ssize_t code = g_dbgmod.dbg_read_memory(ea, buffer, size, errbuf);
*nbytes = code >= 0 ? code : 0;
retcode = code >= 0 ? DRC_OK : DRC_NOPROC;
}
break;
case debugger_t::ev_write_memory:
{
size_t *nbytes = va_arg(va, size_t *);
ea_t ea = va_arg(va, ea_t);
const void *buffer = va_arg(va, void *);
size_t size = va_arg(va, size_t);
errbuf = va_arg(va, qstring *);
ssize_t code = g_dbgmod.dbg_write_memory(ea, buffer, size, errbuf);
*nbytes = code >= 0 ? code : 0;
retcode = code >= 0 ? DRC_OK : DRC_NOPROC;
}
break;
case debugger_t::ev_check_bpt:
{
int *bptvc = va_arg(va, int *);
bpttype_t type = va_argi(va, bpttype_t);
ea_t ea = va_arg(va, ea_t);
int len = va_arg(va, int);
*bptvc = is_ok_bpt(type, ea, len);
retcode = DRC_OK;
}
break;
case debugger_t::ev_update_bpts:
{
int *nbpts = va_arg(va, int *);
update_bpt_info_t *bpts = va_arg(va, update_bpt_info_t *);
int nadd = va_arg(va, int);
int ndel = va_arg(va, int);
errbuf = va_arg(va, qstring *);
retcode = update_bpts(nbpts, bpts, nadd, ndel, errbuf);
}
break;
case debugger_t::ev_update_lowcnds:
{
int *nupdated = va_arg(va, int *);
const lowcnd_t *lowcnds = va_arg(va, const lowcnd_t *);
int nlowcnds = va_arg(va, int);
errbuf = va_arg(va, qstring *);
retcode = g_dbgmod.dbg_update_lowcnds(nupdated, lowcnds, nlowcnds, errbuf);
}
break;
case debugger_t::ev_open_file:
{
const char *file = va_arg(va, const char *);
uint64 *fsize = va_arg(va, uint64 *);
bool readonly = va_argi(va, bool);
retcode = g_dbgmod.dbg_open_file(file, fsize, readonly);
}
break;
case debugger_t::ev_close_file:
{
int fn = va_arg(va, int);
g_dbgmod.dbg_close_file(fn);
retcode = DRC_OK;
}
break;
case debugger_t::ev_read_file:
{
int fn = va_arg(va, int);
qoff64_t off = va_arg(va, qoff64_t);
void *buf = va_arg(va, void *);
size_t size = va_arg(va, size_t);
retcode = g_dbgmod.dbg_read_file(fn, off, buf, size);
}
break;
case debugger_t::ev_write_file:
{
int fn = va_arg(va, int);
qoff64_t off = va_arg(va, qoff64_t);
const void *buf = va_arg(va, const void *);
size_t size = va_arg(va, size_t);
retcode = g_dbgmod.dbg_write_file(fn, off, buf, size);
}
break;
case debugger_t::ev_map_address:
{
ea_t *mapped = va_arg(va, ea_t *);
ea_t ea = va_arg(va, ea_t);
const regval_t *regs = va_arg(va, const regval_t *);
int regnum = va_arg(va, int);
*mapped = g_dbgmod.map_address(ea, regs, regnum);
return DRC_OK;
}
break;
#ifdef GET_DEBMOD_EXTS
case debugger_t::ev_get_debmod_extensions:
{
const void **ext = va_arg(va, const void **);
*ext = GET_DEBMOD_EXTS();
retcode = DRC_OK;
}
break;
#endif
#ifdef HAVE_UPDATE_CALL_STACK
case debugger_t::ev_update_call_stack:
{
thid_t tid = va_argi(va, thid_t);
call_stack_t *trace = va_arg(va, call_stack_t *);
retcode = g_dbgmod.dbg_update_call_stack(tid, trace);
}
break;
#endif
#ifdef HAVE_APPCALL
case debugger_t::ev_appcall:
{
ea_t *blob_ea = va_arg(va, ea_t *);
ea_t func_ea = va_arg(va, ea_t);
thid_t tid = va_arg(va, thid_t);
const func_type_data_t *fti = va_arg(va, const func_type_data_t *);
int nargs = va_arg(va, int);
const regobjs_t *regargs = va_arg(va, const regobjs_t *);
relobj_t *stkargs = va_arg(va, relobj_t *);
regobjs_t *retregs = va_arg(va, regobjs_t *);
errbuf = va_arg(va, qstring *);
debug_event_t *event = va_arg(va, debug_event_t *);
int opts = va_arg(va, int);
qnotused(nargs);
*blob_ea = g_dbgmod.dbg_appcall(func_ea, tid, fti->stkargs, regargs, stkargs, retregs, errbuf, event, opts);
retcode = DRC_OK;
}
break;
case debugger_t::ev_cleanup_appcall:
{
thid_t tid = va_argi(va, thid_t);
retcode = g_dbgmod.dbg_cleanup_appcall(tid);
}
break;
#endif
case debugger_t::ev_eval_lowcnd:
{
thid_t tid = va_argi(va, thid_t);
ea_t ea = va_arg(va, ea_t);
errbuf = va_arg(va, qstring *);
retcode = g_dbgmod.dbg_eval_lowcnd(tid, ea, errbuf);
}
break;
case debugger_t::ev_send_ioctl:
{
int fn = va_arg(va, int);
const void *buf = va_arg(va, const void *);
size_t size = va_arg(va, size_t);
void **poutbuf = va_arg(va, void **);
ssize_t *poutsize = va_arg(va, ssize_t *);
retcode = g_dbgmod.handle_ioctl(fn, buf, size, poutbuf, poutsize);
}
break;
case debugger_t::ev_dbg_enable_trace:
{
thid_t tid = va_arg(va, thid_t);
bool enable = va_argi(va, bool);
int trace_flags = va_arg(va, int);
retcode = g_dbgmod.dbg_enable_trace(tid, enable, trace_flags) ? DRC_OK : DRC_NONE;
}
break;
case debugger_t::ev_is_tracing_enabled:
{
thid_t tid = va_arg(va, thid_t);
int tracebit = va_arg(va, int);
retcode = g_dbgmod.dbg_is_tracing_enabled(tid, tracebit) ? DRC_OK : DRC_NONE;
}
break;
case debugger_t::ev_rexec:
{
const char *cmdline = va_arg(va, const char *);
retcode = g_dbgmod.dbg_rexec(cmdline);
}
break;
#ifdef HAVE_GET_SRCINFO_PATH
case debugger_t::ev_get_srcinfo_path:
{
qstring *path = va_arg(va, qstring *);
ea_t base = va_arg(va, ea_t);
bool ok = g_dbgmod.dbg_get_srcinfo_path(path, base);
retcode = ok ? DRC_OK : DRC_NONE;
}
break;
#endif
case debugger_t::ev_bin_search:
{
ea_t *ea = va_arg(va, ea_t *);
ea_t start_ea = va_arg(va, ea_t);
ea_t end_ea = va_arg(va, ea_t);
const compiled_binpat_vec_t *ptns = va_arg(va, const compiled_binpat_vec_t *);
int srch_flags = va_arg(va, int);
errbuf = va_arg(va, qstring *);
if ( ptns != NULL )
retcode = g_dbgmod.dbg_bin_search(ea, start_ea, end_ea, *ptns, srch_flags, errbuf);
}
break;
}
return retcode;
}
//--------------------------------------------------------------------------
// Initialize debugger plugin
static plugmod_t *idaapi init(void)
{
// copy of the definitions from loader.hpp
// we will delete them after improving the debuggers to use PLUGIN_MULTI.
#define PLUGIN_SKIP nullptr
#define PLUGIN_KEEP ((plugmod_t *)2)
if ( init_plugin() )
{
update_idd_registers();
dbg = &debugger;
plugin_inited = true;
return PLUGIN_KEEP;
}
return PLUGIN_SKIP;
}
//--------------------------------------------------------------------------
// Terminate debugger plugin
static void idaapi term(void)
{
if ( plugin_inited )
{
term_plugin();
plugin_inited = false;
}
// we're being unloaded, clear the 'dbg' pointer if it's ours
if ( dbg == &debugger )
dbg = NULL;
}
//--------------------------------------------------------------------------
// The plugin method - usually is not used for debugger plugins
static bool idaapi run(size_t arg)
{
#ifdef HAVE_PLUGIN_RUN
plugin_run(int(arg));
#else
qnotused(arg);
#endif
return true;
}
//--------------------------------------------------------------------------
//
// DEBUGGER DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
#ifdef SET_DBG_OPTIONS
# define S_SET_DBG_OPTIONS s_set_dbg_options
#else
# define S_SET_DBG_OPTIONS NULL
# define SET_DBG_OPTIONS NULL
#endif
#ifndef S_FILETYPE
# define S_FILETYPE 0
#endif
// arm has no single step mechanism
// DBG_HAS_SET_RESUME_MODE must be set before init_debugger
#if TARGET_PROCESSOR == PLFM_ARM
# define S_DBG_HAS_SET_RESUME_MODE 0
#else
# define S_DBG_HAS_SET_RESUME_MODE DBG_HAS_SET_RESUME_MODE
#endif
#ifndef DEBUGGER_RESMOD
# define DEBUGGER_RESMOD 0
#endif
debugger_t debugger =
{
IDD_INTERFACE_VERSION,
DEBUGGER_NAME,
DEBUGGER_ID,
PROCESSOR_NAME,
DEBUGGER_FLAGS, // flags
DBG_HAS_ATTACH_PROCESS
| DBG_HAS_REQUEST_PAUSE
| DBG_HAS_SET_EXCEPTION_INFO
| DBG_HAS_THREAD_SUSPEND
| DBG_HAS_THREAD_CONTINUE
| S_DBG_HAS_SET_RESUME_MODE
| DBG_HAS_THREAD_GET_SREG_BASE
| DBG_HAS_CHECK_BPT
| DBG_HAS_REXEC, // flags2
REGISTER_CLASSES,
REGISTER_CLASSES_DEFAULT,
REGISTERS,
REGISTERS_SIZE,
MEMORY_PAGE_SIZE,
bpt_code,
sizeof(bpt_code),
S_FILETYPE,
DEBUGGER_RESMOD,
S_SET_DBG_OPTIONS,
idd_notify,
};
//--------------------------------------------------------------------------
//
// PLUGIN DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_HIDE|PLUGIN_DBG, // plugin flags
init, // initialize
term, // terminate. this pointer may be NULL.
run, // invoke plugin
comment, // long comment about the plugin
// it could appear in the status line
// or as a hint
comment, // multiline help about the plugin
wanted_name, // the preferred short name of the plugin
"" // the preferred hotkey to run the plugin
};

View File

@@ -0,0 +1,258 @@
//
// This file is included from other files, do not directly compile it.
// It contains the implementation of debugger plugin callback functions
//
#include <err.h>
#include <name.hpp>
#include <expr.hpp>
#include <segment.hpp>
#include <typeinf.hpp>
//---------------------------------------------------------------------------
//lint -esym(714, rebase_or_warn) not referenced
int rebase_or_warn(ea_t base, ea_t new_base)
{
int code = rebase_program(new_base - base, MSF_FIXONCE);
if ( code != MOVE_SEGM_OK )
{
msg("Failed to rebase program, error code %d\n", code);
warning("IDA failed to rebase the program.\n"
"Most likely it happened because of the debugger\n"
"segments created to reflect the real memory state.\n\n"
"Please stop the debugger and rebase the program manually.\n"
"For that, please select the whole program and\n"
"use Edit, Segments, Rebase program with delta 0x%08a",
new_base - base);
}
return code;
}
//---------------------------------------------------------------------------
void idaapi s_stopped_at_debug_event(thread_name_vec_t *thr_names, bool dlls_added)
{
// Let the debugger module populate the names
g_dbgmod.dbg_stopped_at_debug_event(NULL, dlls_added, thr_names);
if ( dlls_added )
{
#ifndef RPC_CLIENT
// Pass the debug names to the kernel
g_dbgmod.set_debug_names();
#endif
}
}
//--------------------------------------------------------------------------
// This code is compiled for local debuggers (like win32_user.plw)
#ifndef RPC_CLIENT
//--------------------------------------------------------------------------
AS_PRINTF(3,0) ssize_t dvmsg(int code, rpc_engine_t *, const char *format, va_list va)
{
if ( code == 0 )
return vmsg(format, va);
if ( code > 0 )
vwarning(format, va);
else
verror(format, va);
return 0;
}
//--------------------------------------------------------------------------
AS_PRINTF(2,0) void dmsg(rpc_engine_t *rpc, const char *format, va_list va)
{
dvmsg(0, rpc, format, va);
}
//--------------------------------------------------------------------------
AS_PRINTF(2,0) void derror(rpc_engine_t *rpc, const char *format, va_list va)
{
dvmsg(-1, rpc, format, va);
}
//--------------------------------------------------------------------------
AS_PRINTF(2,0) void dwarning(rpc_engine_t *rpc, const char *format, va_list va)
{
dvmsg(1, rpc, format, va);
}
#endif // end of 'local debugger' code
//--------------------------------------------------------------------------
bool lock_begin(void)
{
return true;
}
//--------------------------------------------------------------------------
bool lock_end(void)
{
return true;
}
//--------------------------------------------------------------------------
void report_idc_error(
rpc_engine_t *,
ea_t ea,
error_t code,
ssize_t errval,
const char *errprm)
{
// Copy errval/errprm to the locations expected by qstrerror()
if ( errprm != NULL && errprm != get_error_string(0) )
QPRM(1, errprm);
else if ( code == eOS )
errno = errval;
else
set_error_data(0, errval);
warning("AUTOHIDE NONE\n%a: %s", ea, qstrerror(code));
}
//--------------------------------------------------------------------------
int for_all_debuggers(debmod_visitor_t &v)
{
return v.visit(&g_dbgmod);
}
//--------------------------------------------------------------------------
drc_t idaapi s_write_register(thid_t tid, int reg_idx, const regval_t *value, qstring *errbuf)
{
return g_dbgmod.dbg_write_register(tid, reg_idx, value, errbuf);
}
//--------------------------------------------------------------------------
drc_t idaapi s_read_registers(thid_t tid, int clsmask, regval_t *values, qstring *errbuf)
{
return g_dbgmod.dbg_read_registers(tid, clsmask, values, errbuf);
}
//--------------------------------------------------------------------------
drc_t idaapi s_update_bpts(
int *nbpts,
update_bpt_info_t *bpts,
int nadd,
int ndel,
qstring *errbuf)
{
return g_dbgmod.dbg_update_bpts(nbpts, bpts, nadd, ndel, errbuf);
}
//--------------------------------------------------------------------------
static void update_idd_registers(void)
{
size_t nregs = g_dbgmod.idaregs.nregs();
if ( nregs > 0 )
{
// register classes
debugger.regclasses = g_dbgmod.idaregs.regclasses();
debugger.default_regclasses = 1; // TODO 1 is the general register set
// registers
debugger.nregs = nregs;
debugger.registers = g_dbgmod.idaregs.registers();
}
}
//--------------------------------------------------------------------------
drc_t s_init(uint32_t *flags2, qstring *errbuf)
{
g_dbgmod.debugger_flags = debugger.flags;
drc_t retcode = g_dbgmod.dbg_init(flags2, errbuf);
if ( retcode > DRC_NONE )
update_idd_registers();
return retcode;
}
//--------------------------------------------------------------------------
static drc_t s_attach_process(
pid_t process_id,
int event_id,
int flags,
qstring *errbuf)
{
drc_t retcode = g_dbgmod.dbg_attach_process(process_id, event_id, flags, errbuf);
if ( retcode > DRC_NONE )
update_idd_registers();
return retcode;
}
//--------------------------------------------------------------------------
static drc_t s_start_process(
const char *path,
const char *args,
const char *startdir,
int flags,
const char *input_path,
uint32 input_file_crc32,
qstring *errbuf)
{
drc_t retcode = g_dbgmod.dbg_start_process(path,
args,
startdir,
flags,
input_path,
input_file_crc32,
errbuf);
if ( retcode > DRC_NONE )
update_idd_registers();
return retcode;
}
#ifdef SET_DBG_OPTIONS
//--------------------------------------------------------------------------
// forward declaration
const char *idaapi SET_DBG_OPTIONS(
const char *keyword,
int pri,
int value_type,
const void *value);
//--------------------------------------------------------------------------
static const char *idaapi s_set_dbg_options(
const char *keyword,
int pri,
int value_type,
const void *value)
{
const char *ret = SET_DBG_OPTIONS(keyword, pri, value_type, value);
update_idd_registers();
return ret;
}
#endif
//--------------------------------------------------------------------------
#ifdef REMOTE_DEBUGGER
bool s_open_remote(const char *hostname, int port_number, const char *password, qstring *errbuf)
{
return g_dbgmod.open_remote(hostname, port_number, password, errbuf);
}
drc_t s_close_remote(void)
{
return g_dbgmod.close_remote();
}
#else
bool s_open_remote(const char *, int, const char *, qstring *)
{
return true;
}
drc_t s_close_remote(void)
{
return DRC_OK;
}
#endif
//--------------------------------------------------------------------------
// Local debuggers must call setup_lowcnd_regfuncs() in order to handle
// register read/write requests from low level bpts.
void init_dbg_idcfuncs(bool init)
{
#if !defined(ENABLE_LOWCNDS) \
|| defined(REMOTE_DEBUGGER) \
|| DEBUGGER_ID == DEBUGGER_ID_X86_IA32_BOCHS
qnotused(init);
#else
setup_lowcnd_regfuncs(init ? idc_get_reg_value : NULL,
init ? idc_set_reg_value : NULL);
#endif
}

View File

@@ -0,0 +1,57 @@
#if defined(__NT__) && !defined(__X86__)
//--------------------------------------------------------------------------
static bool path_start_match(const char *s, const char *f)
{
if ( f == NULL || s == NULL || *f == 0 || *s == 0 )
return false;
if ( s == f )
return true;
qstring t1(s);
qstring t2(f);
size_t l1 = t1.length();
size_t l2 = t2.length();
t1.replace("\\", "/");
t2.replace("\\", "/");
if ( t1[l1-1] == '/' )
--l1;
if ( t2[l2-1] == '/' )
--l2;
if ( l1 > l2
|| l1 < l2 && t2[l1] != '/' )
{
return false;
}
return memicmp(t1.c_str(), t2.c_str(), l1) == 0;
}
//--------------------------------------------------------------------------
static void replace_system32(char *path, size_t sz)
{
char spath[MAXSTR];
spath[0] = 0;
GetSystemDirectoryA(spath, sizeof(spath));
if ( spath[0] == 0 || !path_start_match(spath, path) )
return;
char wpath[MAXSTR];
wpath[0] = 0;
GetSystemWow64Directory(wpath, sizeof(wpath));
if ( wpath[0] == 0 || path_start_match(wpath, spath) )
return;
size_t len = strlen(wpath);
if ( wpath[len-1] == '/' || wpath[len-1] == '\\' )
wpath[len-1] = 0;
len = strlen(spath);
if ( spath[len-1] == '/' || spath[len-1] == '\\' )
{
--len;
path[len] = 0;
}
qstring n;
n.sprnt("%s%s", wpath, &path[len]);
qstrncpy(path, n.c_str(), sz);
}
#else
#define replace_system32(PATH, SZ) do {} while ( false )
#endif

View File

@@ -0,0 +1,246 @@
// This file is included in the debugger stub that runs on the computer with IDA
#include <pro.h>
#include <name.hpp>
#include <diskio.hpp>
#include "dbg_rpc_client.h"
#include "dbg_rpc_hlp.h"
#include "debmod.h"
//--------------------------------------------------------------------------
// check and send to the remote server the specified stub
// do it only if its crc does not match the specified crc
// this function runs on the local machine with ida interface
static uchar *sync_stub(const char *fname, uint32 crc, size_t *psize)
{
bool complain = true;
uchar *retval = NULL;
char path[QMAXPATH];
if ( getsysfile(path, sizeof(path), fname, NULL) != NULL )
{
linput_t *li = open_linput(path, false);
if ( li != NULL )
{
int64 size = qlsize(li);
if ( size > 0 )
{
bytevec_t buf;
buf.resize(size);
if ( qlread(li, buf.begin(), size) == size )
{
complain = false;
if ( calc_crc32(0, buf.begin(), size) != crc )
{
*psize = size;
retval = buf.extract();
}
else
{
msg("Kernel debugger stub is up to date...\n");
*psize = 1; // signal ok
}
}
}
close_linput(li);
}
}
if ( complain )
warning("AUTOHIDE NONE\nCould not find/read debugger stub %s", fname);
return retval;
}
//--------------------------------------------------------------------------
dbg_rpc_client_t::dbg_rpc_client_t(idarpc_stream_t *_irs)
: dbg_rpc_engine_t(/*is_client=*/ true),
client_irs(_irs)
{
pending_event.clear_all();
verbose = false;
recv_timeout = RECV_TIMEOUT_PERIOD;
}
//-------------------------------------------------------------------------
void dbg_rpc_client_t::my_update_wait_dialog(
const char *message,
const rpc_packet_t *rp)
{
if ( send_request_data.wait_dialog_displayed )
{
if ( rp->code != send_request_data.code )
replace_wait_box("%s", message);
}
else
{
show_wait_box("%s", message);
send_request_data.wait_dialog_displayed = true;
}
send_request_data.code = rp->code;
}
//--------------------------------------------------------------------------
// requests received from the server.
// here the client handles certain server -> client requests
bytevec_t dbg_rpc_client_t::on_send_request_interrupt(const rpc_packet_t *rp)
{
memory_deserializer_t mmdsr(rp+1, rp->length);
bytevec_t req = prepare_rpc_packet(RPC_OK);
switch ( rp->code )
{
// send_debug_names_to_ida() is thread safe
case RPC_SET_DEBUG_NAMES:
{
my_update_wait_dialog("Downloading Symbols", rp);
int qty = mmdsr.unpack_dd();
ea_t *addrs = OPERATOR_NEW(ea_t, qty);
char **names = OPERATOR_NEW(char *, qty);
qstring name;
ea_t old = 0;
for ( int i=0; i < qty; i++ )
{
adiff_t o2 = mmdsr.unpack_ea64();
if ( mmdsr.unpack_dd() )
o2 = -o2;
old += o2;
addrs[i] = old;
int oldlen = mmdsr.unpack_dd();
QASSERT(1203, oldlen >= 0 && oldlen <= name.length());
//keep the prefix
name.resize(oldlen);
if ( !mmdsr.unpack_str(&name) )
INTERR(1294);
names[i] = qstrdup(name.c_str());
}
int result = send_debug_names_to_ida(addrs, names, qty);
verb(("set_debug_name(qty=%d) => %d\n", qty, result));
req.pack_dd(result);
for ( int i=0; i < qty; i++ )
qfree(names[i]);
delete [] addrs;
delete [] names;
}
break;
// import_dll() is thread safe
case RPC_IMPORT_DLL:
{
my_update_wait_dialog("Importing DLLs", rp);
ea_t base = mmdsr.unpack_ea64();
const char *path = mmdsr.unpack_str();
int n = mmdsr.unpack_dd();
const void *bytes = mmdsr.unpack_obj_inplace(n);
bytevec_t uuid(bytes, n);
int result = import_dll(import_request_t(base, path, uuid));
verb(("import_dll(base=%a, path=%s) => %d\n", base, path, result));
req.pack_dd(result);
}
break;
// send_debug_event_to_ida() is thread safe
case RPC_HANDLE_DEBUG_EVENT:
{
debug_event_t ev;
extract_debug_event(&ev, mmdsr);
int rqflags = mmdsr.unpack_dd();
int code = send_debug_event_to_ida(&ev, rqflags);
req.pack_dd(code);
}
break;
// sync_stub() is thread safe
case RPC_SYNC_STUB:
{
const char *fname = mmdsr.unpack_str();
uint32 crc = mmdsr.unpack_dd();
// security problem: the debugger server should not be able to
// read an arbitrary file on the local computer. therefore we completely
// ignore the file name and use a hardcoded name.
qnotused(fname);
fname = "ida_kdstub.dll";
size_t size = 0;
uchar *contents = sync_stub(fname, crc, &size);
req.pack_dd((uint32)size);
if ( contents != NULL )
{
req.append(contents, size);
qfree(contents);
}
}
break;
// msg/error/warning are thread safe
case RPC_ERROR:
case RPC_MSG:
case RPC_WARNING:
{
const char *str = mmdsr.unpack_str();
if ( *str != '\0' )
{
if ( rp->code == RPC_MSG )
msg("%s", str);
else if ( rp->code == RPC_ERROR )
error("%s", str);
else
warning("%s", str);
}
}
break;
// no external functions are called
case RPC_EVENT:
{
extract_debug_event(&pending_event, mmdsr);
has_pending_event = true;
req = prepare_rpc_packet(RPC_EVOK);
verbev(("got event, storing it and sending RPC_EVOK\n"));
}
break;
// i doubt that this code is used on the client side
// ioctl_handler is NULL
case RPC_IOCTL:
{
int code = handle_ioctl_packet(req, mmdsr.ptr, mmdsr.end);
if ( code != RPC_OK )
return prepare_rpc_packet((uchar)code);
}
break;
// report_idc_error() is thread safe
case RPC_REPORT_IDC_ERROR:
{
ea_t ea = mmdsr.unpack_ea64();
error_t code = mmdsr.unpack_dd();
const char *errprm;
ssize_t errval;
if ( mmdsr.unpack_db() )
{
errprm = mmdsr.unpack_str();
errval = (ssize_t)errprm;
}
else
{
errprm = NULL;
errval = mmdsr.unpack_ea64();
}
report_idc_error(NULL, ea, code, errval, errprm);
}
break;
default:
return prepare_rpc_packet(RPC_UNK);
}
return req;
}
//-------------------------------------------------------------------------
void dbg_rpc_client_t::on_send_request_end(const rpc_packet_t *)
{
if ( send_request_data.wait_dialog_displayed )
hide_wait_box();
send_request_data.reset();
}

View File

@@ -0,0 +1,35 @@
#ifndef __RPC_CLIENT__
#define __RPC_CLIENT__
#include "dbg_rpc_engine.h"
class dbg_rpc_client_t: public dbg_rpc_engine_t
{
protected:
debug_event_t pending_event;
idarpc_stream_t *client_irs;
bool verbose;
struct send_request_data_t
{
uchar code;
bool wait_dialog_displayed;
send_request_data_t() { reset(); }
void reset() { code = uchar(-1); wait_dialog_displayed = false; }
};
send_request_data_t send_request_data;
void my_update_wait_dialog(const char *message, const rpc_packet_t *rp);
virtual bytevec_t on_send_request_interrupt(const rpc_packet_t *rp) override;
virtual void on_send_request_end(const rpc_packet_t *result) override;
public:
dbg_rpc_client_t(idarpc_stream_t *irs);
virtual ~dbg_rpc_client_t() {}
virtual idarpc_stream_t *get_irs() const override { return client_irs; }
};
#endif

View File

@@ -0,0 +1,97 @@
#include <network.hpp>
#include "dbg_rpc_engine.h"
//-------------------------------------------------------------------------
dbg_rpc_engine_t::dbg_rpc_engine_t(bool _is_client)
: rpc_engine_t(_is_client),
has_pending_event(false),
poll_debug_events(false)
{
}
//--------------------------------------------------------------------------
// sends a request and waits for a reply
// may occasionally send another request based on the reply
rpc_packet_t *dbg_rpc_engine_t::send_request_and_receive_reply(bytevec_t &req, int flags)
{
bool displayed = false;
rpc_packet_t *result = NULL;
while ( true )
{
if ( displayed && user_cancelled() )
req = prepare_rpc_packet(RPC_CANCELLED);
if ( !req.empty() )
{
int code = send_data(req);
if ( code != 0 || (flags & PREQ_GET_EVENT) != 0 )
break;
rpc_packet_t *reqp = (rpc_packet_t *)req.begin();
if ( reqp->code == RPC_ERROR )
qexit(1); // sent error packet, may die now
}
rpc_packet_t *rp = recv_packet();
if ( rp == NULL )
break;
switch ( rp->code )
{
case RPC_UNK:
dwarning("rpc: remote did not understand our request");
goto FAILURE;
case RPC_MEM:
dwarning("rpc: no remote memory");
goto FAILURE;
case RPC_CANCELLED:
msg("rpc: user cancelled the operation\n");
goto FAILURE;
case RPC_OK:
result = rp;
goto END;
default:
// other replies are passed to the handler
break;
}
if ( !logged_in )
{
lprintf("Exploit packet has been detected and ignored\n");
FAILURE:
qfree(rp);
break;
}
//handle actual command in the request
//FIXME: use a better function name
req = on_send_request_interrupt(rp);
qfree(rp);
}
END:
on_send_request_end(result);
return result;
}
//-------------------------------------------------------------------------
int dbg_rpc_engine_t::_send_request_get_int_result(
bytevec_t &req,
int failure_code,
qstring *errbuf)
{
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return failure_code;
memory_deserializer_t mmdsr(rp+1, rp->length);
int rc = mmdsr.unpack_dd();
if ( rc < 0 && errbuf != NULL )
*errbuf = mmdsr.unpack_str();
qfree(rp);
return rc;
}

View File

@@ -0,0 +1,37 @@
#ifndef __DBG_RPC_ENGINE__
#define __DBG_RPC_ENGINE__
#include <pro.h>
#include <idd.hpp>
#include <network.hpp>
//-------------------------------------------------------------------------
class dbg_rpc_engine_t : public rpc_engine_t
{
public:
bool has_pending_event;
bool poll_debug_events;
dbg_rpc_engine_t(bool _is_client);
#define PREQ_MUST_LOGIN 0x01
#define PREQ_GET_EVENT 0x02
rpc_packet_t *send_request_and_receive_reply(bytevec_t &pkt, int flags);
virtual rpc_packet_t *send_request_and_receive_reply(bytevec_t &pkt) override
{
return send_request_and_receive_reply(pkt, 0);
}
protected:
int send_request_get_long_result(bytevec_t &pkt) { return _send_request_get_int_result(pkt, -1, NULL); }
drc_t send_request_get_drc_result(bytevec_t &pkt, qstring *errbuf) { return drc_t(_send_request_get_int_result(pkt, DRC_NETERR, errbuf)); }
virtual bytevec_t on_send_request_interrupt(const rpc_packet_t *rp) = 0;
virtual void on_send_request_end(const rpc_packet_t *result) newapi { qnotused(result); }
private:
int _send_request_get_int_result(bytevec_t &pkt, int failure_code, qstring *errbuf);
};
#endif // __DBG_RPC_ENGINE__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
#ifndef __DBG_RPC_HANDLER__
#define __DBG_RPC_HANDLER__
#include <network.hpp>
#include "dbg_rpc_engine.h"
#define MIN_SERVER_IOCTL 0x01000000
#include "debmod.h"
struct dbgsrv_dispatcher_t;
//-------------------------------------------------------------------------
class dbg_rpc_handler_t
: public client_handler_t,
public dbg_rpc_engine_t
{
public:
dbg_rpc_handler_t(idarpc_stream_t *_irs, dbgsrv_dispatcher_t *_dispatcher);
virtual ~dbg_rpc_handler_t();
virtual bool handle() override;
virtual void shutdown_gracefully(int signum) override;
private:
debug_event_t ev;
debug_event_t pending_event;
debmod_t *dbg_mod;
dbgsrv_dispatcher_t *dispatcher;
DECLARE_UNCOPYABLE(dbg_rpc_handler_t);
void append_start_or_attach(bytevec_t &req, drc_t drc, const qstring &errbuf) const;
int poll_events(int timeout_ms);
void extract_path_and_arch(
const char **out_file_path,
int *out_arch,
int *out_is_be,
memory_deserializer_t &mmdsr) const;
int on_recv_packet_progress(bool *performed);
protected:
void rpc_update_lowcnds(bytevec_t &rcmd, memory_deserializer_t &mmdsr);
int rpc_update_bpts(bytevec_t &rcmd, memory_deserializer_t &mmdsr);
drc_t rpc_attach_process(qstring *errbuf, memory_deserializer_t &mmdsr);
bool check_broken_connection(pid_t pid);
virtual int handle_server_ioctl(int fn, void **out, ssize_t *outsz, memory_deserializer_t &mmdsr) newapi;
virtual bytevec_t on_send_request_interrupt(const rpc_packet_t *rp) override;
public:
void set_debugger_instance(debmod_t *instance);
debmod_t *get_debugger_instance();
void prepare_broken_connection();
bool rpc_sync_stub(const char *server_stub_name, const char *ida_stub_name);
int send_debug_names_to_ida(ea_t *ea, const char *const *names, int qty);
int send_debug_event_to_ida(const debug_event_t *ev, int rqflags);
void process_import_requests(const import_infos_t &infos);
virtual idarpc_stream_t *get_irs() const override { return irs; }
virtual bool get_broken_connection(void) override;
virtual void set_broken_connection(void) override;
int kill_process(void); // returns 0-ok, >0-failed, after that many seconds
};
// defined only in the single threaded version of the server:
extern dbg_rpc_handler_t *g_global_server;
#endif // __DBG_RPC_HANDLER__

View File

@@ -0,0 +1,70 @@
#ifndef __DBG_RPC_HANDLER_IOCTLS__
#define __DBG_RPC_HANDLER_IOCTLS__
// Note: the dbg_rpc_handler_t implementation will consider all
// IOCTL IDs >= 0x01000000 as being server IOCTLs, and those will
// consequently *not* be passed to the debugger module.
#define MIN_SERVER_IOCTL 0x01000000
#define DWARF_RPCSRV_IOCTL_OK 0
#define DWARF_RPCSRV_IOCTL_ERROR -1
enum rpcsrv_ioctl_t
{
// Get DWARF sections information.
//
// client->server
// (unpacked) char * : file_path (on the server's disk.)
// (packed) uint32 : processor ID (as in: ph.id)
// server->client
// (unpacked) byte : DWARF info found
// (packed) uint32 : is_64 (0 - no, !=0 - yes)
// (packed) uint32 : is_msb (0 - no, !=0 - yes)
// (packed) uint64 : declared load address
// (packed) uint32 : number of DWARF section infos.
// (packed) sec info : DWARF section info, N times.
// Returns: 0 - ok
// !=0 - error (text in output buffer.)
//
// The structure of a "sec info" is:
// (packed) uint64 address_in_memory
// (packed) uint64 size (in bytes)
// (packed) uint16 section_index
// (unpacked) char * section_name
rpcsrv_ioctl_dwarf_secinfo = MIN_SERVER_IOCTL + 1,
// Get DWARF section data.
//
// client->server
// (unpacked) char * : file_path (on the server's disk.)
// (packed) uint32 : processor ID (as in: ph.id)
// (packed) uint16 : DWARF section index (as returned by 'rpcsrv_ioctl_dwarf_secinfo')
// server->client
// (unpacked) byte * : DWARF section data.
// Returns: 0 - ok
// !=0 - error
rpcsrv_ioctl_dwarf_secdata,
#if defined(TESTABLE_BUILD)
// Set path to look for ELF/DWARF companion files, per-PID
//
// This is strictly meant for testing, where tests can store
// files in unusual places on the leasing debug server's volume.
//
// client->server
// (packed) uint32 : the PID
// (unpacked) char * : directory path (on the server's disk.)
// server->client
// Nothing
// Returns: 0 - ok
// != 0 - error
rpcsrv_ioctl_set_elf_debug_file_directory_for_pid = 2 * MIN_SERVER_IOCTL + 1,
#endif
};
#if defined(TESTABLE_BUILD) && defined(__LINUX__)
void set_elf_debug_file_directory_for_pid(int pid, const char *path);
const char *get_elf_debug_file_directory_for_pid(int pid);
#endif
#endif // __DBG_RPC_HANDLER_IOCTLS__

View File

@@ -0,0 +1,367 @@
#include <segment.hpp>
#include <typeinf.hpp>
#include "dbg_rpc_hlp.h"
//--------------------------------------------------------------------------
void append_memory_info(bytevec_t &s, const memory_info_t *meminf)
{
s.pack_ea64(meminf->sbase);
s.pack_ea64(meminf->start_ea - (meminf->sbase << 4));
s.pack_ea64(meminf->size());
s.pack_dd(meminf->perm | (meminf->bitness<<4));
s.pack_str(meminf->name.c_str());
s.pack_str(meminf->sclass.c_str());
}
//--------------------------------------------------------------------------
void extract_memory_info(memory_info_t *meminf, memory_deserializer_t &mmdsr)
{
meminf->sbase = mmdsr.unpack_ea64();
meminf->start_ea = ea_t(meminf->sbase << 4) + mmdsr.unpack_ea64();
meminf->end_ea = meminf->start_ea + mmdsr.unpack_ea64();
int v = mmdsr.unpack_dd();
meminf->perm = uchar(v) & SEGPERM_MAXVAL;
meminf->bitness = uchar(v>>4);
meminf->name = mmdsr.unpack_str();
meminf->sclass = mmdsr.unpack_str();
}
//--------------------------------------------------------------------------
void append_scattered_segm(bytevec_t &s, const scattered_segm_t *ss)
{
s.pack_ea64(ss->start_ea);
s.pack_ea64(ss->end_ea);
s.pack_str(ss->name.c_str());
}
//--------------------------------------------------------------------------
void extract_scattered_segm(scattered_segm_t *ss, memory_deserializer_t &mmdsr)
{
ss->start_ea = mmdsr.unpack_ea64();
ss->end_ea = mmdsr.unpack_ea64();
ss->name = mmdsr.unpack_str();
}
//--------------------------------------------------------------------------
void append_process_info_vec(bytevec_t &s, const procinfo_vec_t *procs)
{
size_t size = procs->size();
s.pack_dd(size);
for ( size_t i = 0; i < size; i++ )
{
const process_info_t &pi = procs->at(i);
s.pack_dd(pi.pid);
s.pack_str(pi.name.c_str());
}
}
//--------------------------------------------------------------------------
void extract_process_info_vec(procinfo_vec_t *procs, memory_deserializer_t &mmdsr)
{
size_t size = mmdsr.unpack_dd();
for ( size_t i = 0; i < size; i++ )
{
process_info_t &pi = procs->push_back();
pi.pid = mmdsr.unpack_dd();
pi.name = mmdsr.unpack_str();
}
}
//--------------------------------------------------------------------------
void append_module_info(bytevec_t &s, const modinfo_t *modinf)
{
s.pack_str(modinf->name);
s.pack_ea64(modinf->base);
s.pack_ea64(modinf->size);
s.pack_ea64(modinf->rebase_to);
}
//--------------------------------------------------------------------------
void extract_module_info(modinfo_t *modinf, memory_deserializer_t &mmdsr)
{
modinf->name = mmdsr.unpack_str();
modinf->base = mmdsr.unpack_ea64();
modinf->size = mmdsr.unpack_ea64();
modinf->rebase_to = mmdsr.unpack_ea64();
}
//--------------------------------------------------------------------------
void append_exception(bytevec_t &s, const excinfo_t *e)
{
s.pack_dd(e->code);
s.pack_dd(e->can_cont);
s.pack_ea64(e->ea);
s.pack_str(e->info);
}
//--------------------------------------------------------------------------
void extract_exception(excinfo_t *exc, memory_deserializer_t &mmdsr)
{
exc->code = mmdsr.unpack_dd();
exc->can_cont = mmdsr.unpack_dd() != 0;
exc->ea = mmdsr.unpack_ea64();
exc->info = mmdsr.unpack_str();
}
//--------------------------------------------------------------------------
void extract_debug_event(debug_event_t *ev, memory_deserializer_t &mmdsr)
{
ev->set_eid(event_id_t(mmdsr.unpack_dd()));
ev->pid = mmdsr.unpack_dd();
ev->tid = mmdsr.unpack_dd();
ev->ea = mmdsr.unpack_ea64();
ev->handled = mmdsr.unpack_dd() != 0;
switch ( ev->eid() )
{
case NO_EVENT: // Not an interesting event
case STEP: // One instruction executed
case PROCESS_DETACHED: // Detached from process
default:
break;
case PROCESS_STARTED: // New process started
case PROCESS_ATTACHED: // Attached to running process
case LIB_LOADED: // New library loaded
extract_module_info(&ev->modinfo(), mmdsr);
break;
case PROCESS_EXITED: // Process stopped
case THREAD_EXITED: // Thread stopped
ev->exit_code() = mmdsr.unpack_dd();
break;
case BREAKPOINT: // Breakpoint reached
extract_breakpoint(&ev->bpt(), mmdsr);
break;
case EXCEPTION: // Exception
extract_exception(&ev->exc(), mmdsr);
break;
case THREAD_STARTED: // New thread started
case LIB_UNLOADED: // Library unloaded
case INFORMATION: // User-defined information
ev->info() = mmdsr.unpack_str();
break;
}
}
//--------------------------------------------------------------------------
void append_debug_event(bytevec_t &s, const debug_event_t *ev)
{
s.pack_dd(ev->eid());
s.pack_dd(ev->pid);
s.pack_dd(ev->tid);
s.pack_ea64(ev->ea);
s.pack_dd(ev->handled);
switch ( ev->eid() )
{
case NO_EVENT: // Not an interesting event
case STEP: // One instruction executed
case PROCESS_DETACHED: // Detached from process
default:
break;
case PROCESS_STARTED: // New process started
case PROCESS_ATTACHED: // Attached to running process
case LIB_LOADED: // New library loaded
append_module_info(s, &ev->modinfo());
break;
case PROCESS_EXITED: // Process stopped
case THREAD_EXITED: // Thread stopped
s.pack_dd(ev->exit_code());
break;
case BREAKPOINT: // Breakpoint reached
append_breakpoint(s, &ev->bpt());
break;
case EXCEPTION: // Exception
append_exception(s, &ev->exc());
break;
case THREAD_STARTED: // New thread started
case LIB_UNLOADED: // Library unloaded
case INFORMATION: // User-defined information
s.pack_str(ev->info());
break;
}
}
//--------------------------------------------------------------------------
exception_info_t *extract_exception_info(int qty, memory_deserializer_t &mmdsr)
{
exception_info_t *extable = NULL;
if ( qty > 0 )
{
extable = OPERATOR_NEW(exception_info_t, qty);
for ( int i=0; i < qty; i++ )
{
extable[i].code = mmdsr.unpack_dd();
extable[i].flags = mmdsr.unpack_dd();
extable[i].name = mmdsr.unpack_str();
extable[i].desc = mmdsr.unpack_str();
}
}
return extable;
}
//--------------------------------------------------------------------------
void append_exception_info(bytevec_t &s, const exception_info_t *table, int qty)
{
for ( int i=0; i < qty; i++ )
{
s.pack_dd(table[i].code);
s.pack_dd(table[i].flags);
s.pack_str(table[i].name.c_str());
s.pack_str(table[i].desc.c_str());
}
}
//--------------------------------------------------------------------------
void extract_call_stack(call_stack_t *trace, memory_deserializer_t &mmdsr)
{
int n = mmdsr.unpack_dd();
trace->resize(n);
for ( int i=0; i < n; i++ )
{
call_stack_info_t &ci = (*trace)[i];
ci.callea = mmdsr.unpack_ea64();
ci.funcea = mmdsr.unpack_ea64();
ci.fp = mmdsr.unpack_ea64();
ci.funcok = mmdsr.unpack_dd() != 0;
}
}
//--------------------------------------------------------------------------
void append_call_stack(bytevec_t &s, const call_stack_t &trace)
{
int n = trace.size();
s.pack_dd(n);
for ( int i=0; i < n; i++ )
{
const call_stack_info_t &ci = trace[i];
s.pack_ea64(ci.callea);
s.pack_ea64(ci.funcea);
s.pack_ea64(ci.fp);
s.pack_dd(ci.funcok);
}
}
//--------------------------------------------------------------------------
void extract_regobjs(
regobjs_t *regargs,
bool with_values,
memory_deserializer_t &mmdsr)
{
int n = mmdsr.unpack_dd();
regargs->resize(n);
for ( int i=0; i < n; i++ )
{
regobj_t &ro = (*regargs)[i];
ro.regidx = mmdsr.unpack_dd();
int size = mmdsr.unpack_dd();
ro.value.resize(size);
if ( with_values )
{
ro.relocate = mmdsr.unpack_dd();
mmdsr.unpack_obj(ro.value.begin(), size);
}
}
}
//--------------------------------------------------------------------------
static void extract_relobj(relobj_t *stkargs, memory_deserializer_t &mmdsr)
{
int n = mmdsr.unpack_dd();
stkargs->resize(n);
mmdsr.unpack_obj(stkargs->begin(), n);
stkargs->base = mmdsr.unpack_ea64();
n = mmdsr.unpack_dd();
stkargs->ri.resize(n);
mmdsr.unpack_obj(stkargs->ri.begin(), n);
}
//--------------------------------------------------------------------------
void extract_appcall(
regobjs_t *regargs,
relobj_t *stkargs,
regobjs_t *retregs,
memory_deserializer_t &mmdsr)
{
extract_regobjs(regargs, true, mmdsr);
extract_relobj(stkargs, mmdsr);
if ( retregs != NULL )
extract_regobjs(retregs, false, mmdsr);
}
//--------------------------------------------------------------------------
void append_regobjs(bytevec_t &s, const regobjs_t &regargs, bool with_values)
{
s.pack_dd(regargs.size());
for ( size_t i=0; i < regargs.size(); i++ )
{
const regobj_t &ro = regargs[i];
s.pack_dd(ro.regidx);
s.pack_dd(ro.value.size());
if ( with_values )
{
s.pack_dd(ro.relocate);
s.append(ro.value.begin(), ro.value.size());
}
}
}
//--------------------------------------------------------------------------
static void append_relobj(bytevec_t &s, const relobj_t &stkargs)
{
s.pack_buf(stkargs.begin(), stkargs.size());
s.pack_ea64(stkargs.base);
s.pack_buf(stkargs.ri.begin(), stkargs.ri.size());
}
//--------------------------------------------------------------------------
void append_appcall(
bytevec_t &s,
const regobjs_t &regargs,
const relobj_t &stkargs,
const regobjs_t *retregs)
{
append_regobjs(s, regargs, true);
append_relobj(s, stkargs);
if ( retregs != NULL )
append_regobjs(s, *retregs, false);
}
//--------------------------------------------------------------------------
void append_regvals(bytevec_t &s, const regval_t *values, int n, const uchar *regmap)
{
for ( int i=0; i < n; i++ )
if ( regmap == NULL || test_bit(regmap, i) )
append_regval(s, values[i]);
}
//--------------------------------------------------------------------------
void extract_debapp_attrs(debapp_attrs_t *attrs, memory_deserializer_t &mmdsr)
{
attrs->addrsize = mmdsr.unpack_dd();
attrs->platform = mmdsr.unpack_str();
}
//--------------------------------------------------------------------------
void append_debapp_attrs(bytevec_t &s, const debapp_attrs_t &attrs)
{
s.pack_dd(attrs.addrsize);
s.pack_str(attrs.platform.c_str());
}
//--------------------------------------------------------------------------
void extract_dynamic_register_set(
dynamic_register_set_t *idaregs,
memory_deserializer_t &mmdsr)
{
deserialize_dynamic_register_set(idaregs, mmdsr);
}
//--------------------------------------------------------------------------
void append_dynamic_register_set(
bytevec_t &s,
dynamic_register_set_t &idaregs)
{
serialize_dynamic_register_set(&s, idaregs);
}

View File

@@ -0,0 +1,80 @@
#ifndef __DBG_RPC_HLP__
#define __DBG_RPC_HLP__
#include <pro.h>
#include <range.hpp>
#include <idd.hpp>
#include <network.hpp>
void append_regvals(bytevec_t &s, const regval_t *values, int n, const uchar *regmap);
void append_debug_event(bytevec_t &s, const debug_event_t *ev);
void extract_debug_event(debug_event_t *ev, memory_deserializer_t &mmdsr);
void extract_exception(excinfo_t *exc, memory_deserializer_t &mmdsr);
void append_exception(bytevec_t &s, const excinfo_t *e);
inline void append_breakpoint(bytevec_t &s, const bptaddr_t *info)
{
s.pack_ea64(info->hea);
s.pack_ea64(info->kea);
}
inline void extract_breakpoint(bptaddr_t *info, memory_deserializer_t &mmdsr)
{
info->hea = mmdsr.unpack_ea64();
info->kea = mmdsr.unpack_ea64();
}
void extract_module_info(modinfo_t *info, memory_deserializer_t &mmdsr);
void append_module_info(bytevec_t &s, const modinfo_t *info);
void extract_process_info_vec(procinfo_vec_t *procs, memory_deserializer_t &mmdsr);
void append_process_info_vec(bytevec_t &s, const procinfo_vec_t *procs);
void extract_call_stack(call_stack_t *trace, memory_deserializer_t &mmdsr);
void append_call_stack(bytevec_t &s, const call_stack_t &trace);
void extract_regobjs(regobjs_t *regargs, bool with_values, memory_deserializer_t &mmdsr);
void append_regobjs(bytevec_t &s, const regobjs_t &regargs, bool with_values);
void extract_appcall(
regobjs_t *regargs,
relobj_t *stkargs,
regobjs_t *retregs,
memory_deserializer_t &mmdsr);
void append_appcall(
bytevec_t &s,
const regobjs_t &regargs,
const relobj_t &stkargs,
const regobjs_t *retregs);
void extract_debapp_attrs(
debapp_attrs_t *attrs,
memory_deserializer_t &mmdsr);
void append_debapp_attrs(bytevec_t &s, const debapp_attrs_t &attrs);
void extract_dynamic_register_set(
dynamic_register_set_t *idaregs,
memory_deserializer_t &mmdsr);
void append_dynamic_register_set(
bytevec_t &s,
dynamic_register_set_t &idaregs);
inline void append_type(bytevec_t &s, const type_t *str)
{
s.pack_str((char *)str);
}
void append_type(bytevec_t &s, const tinfo_t &tif);
void extract_type(tinfo_t *tif, memory_deserializer_t &mmdsr);
void extract_memory_info(memory_info_t *info, memory_deserializer_t &mmdsr);
void append_memory_info(bytevec_t &s, const memory_info_t *info);
void extract_scattered_segm(scattered_segm_t *ss, memory_deserializer_t &mmdsr);
void append_scattered_segm(bytevec_t &s, const scattered_segm_t *ss);
void append_exception_info(bytevec_t &s, const exception_info_t *table, int qty);
exception_info_t *extract_exception_info(int qty, memory_deserializer_t &mmdsr);
#endif // __DBG_RPC_HLP__

19
idasdk75/dbg/deb_arm.hpp Normal file
View File

@@ -0,0 +1,19 @@
#ifndef __DEB_ARM__
#define __DEB_ARM__
#include <ua.hpp>
#include <idd.hpp>
#define MEMORY_PAGE_SIZE 0x1000
#define ARM_BPT_CODE { 0xF0, 0x01, 0xF0, 0xE7 } // und #10
#define AARCH64_BPT_CODE { 0x00, 0x00, 0x20, 0xD4 } // brk #0
#define ARM_BPT_SIZE 4 // size of BPT instruction
#define ARM_T 20 // number of virtual T segment register in IDA
// it controls thumb/arm mode.
int is_arm_valid_bpt(bpttype_t type, ea_t ea, int len);
#endif

47
idasdk75/dbg/deb_pc.hpp Normal file
View File

@@ -0,0 +1,47 @@
#ifndef __DEB_PC__
#define __DEB_PC__
#include <ua.hpp>
#include <range.hpp>
#include <idd.hpp>
#define MEMORY_PAGE_SIZE 0x1000
#define X86_BPT_CODE { 0xCC }
#define MAX_BPT 4 // maximal number of hardware breakpoints
#define X86_BPT_SIZE 1 // size of 0xCC instruction
#define EFLAGS_TRAP_FLAG 0x00000100
//--------------------------------------------------------------------------
drc_t idaapi x86_read_registers(thid_t thread_id, int clsmask, regval_t *values, qstring *errbuf);
drc_t idaapi x86_write_register(thid_t thread_id, int regidx, const regval_t *value, qstring *errbuf);
int is_x86_valid_bpt(bpttype_t type, ea_t ea, int len);
//--------------------------------------------------------------------------
inline int check_x86_hwbpt(bpttype_t type, ea_t ea, int len)
{
if ( type != BPT_RDWR // type is good?
&& type != BPT_WRITE
&& type != BPT_EXEC )
{
return BPT_BAD_TYPE;
}
if ( len != 1 // is length good?
&& (type == BPT_EXEC // instruction hardware breakpoint only accepts the len of one byte
|| (len != 2 && len != 4
#ifndef __X86__
&& len != 8
#endif
)) )
{
return BPT_BAD_LEN;
}
if ( (ea & (len-1)) != 0 ) // is alignment good?
return BPT_BAD_ALIGN;
return BPT_OK;
}
#endif

1329
idasdk75/dbg/debmod.cpp Normal file

File diff suppressed because it is too large Load Diff

741
idasdk75/dbg/debmod.h Normal file
View File

@@ -0,0 +1,741 @@
#ifndef __DEBUGGER_MODULE__
#define __DEBUGGER_MODULE__
//
//
// This is the base debmod_t class definition
// From this class all debugger code must inherite and specialize
//
// Some OS specific functions must be implemented:
// bool init_subsystem();
// bool term_subsystem();
// debmod_t *create_debug_session(void *);
// int create_thread(thread_cb_t thread_cb, void *context);
//
#include <map>
#include <deque>
#include <set>
#include <algorithm>
#include <pro.h>
#include <idd.hpp>
#include <network.hpp>
//--------------------------------------------------------------------------
extern debugger_t debugger;
//--------------------------------------------------------------------------
struct name_info_t
{
eavec_t addrs;
qvector<char *> names;
void clear(void)
{
addrs.clear();
names.clear();
}
};
//--------------------------------------------------------------------------
// Extended process info
struct ext_process_info_t : public process_info_t
{
int addrsize; // process bitness 32bit - 4, 64bit - 8, 0 - unknown
qstring ext_name; // human-readable name (e.g. with command line agrs)
void copy_to(process_info_t *dst)
{
dst->pid = pid;
dst->name = ext_name.empty() ? name : ext_name;
}
};
typedef qvector<ext_process_info_t> procvec_t;
//--------------------------------------------------------------------------
// Very simple class to store pending events
enum queue_pos_t
{
IN_FRONT,
IN_BACK
};
//--------------------------------------------------------------------------
struct pagebpt_data_t
{
ea_t ea; // address of the bpt as specified by the user
ea_t page_ea; // real address of the bpt as written to the process
int user_len; // breakpoint length as specified by the user
int aligned_len; // breakpoint length aligned to the page size
int real_len; // real length of the breakpoint as written to the process
uint32 old_prot; // old page protections (before writing the bpt to the process)
// if 0, the bpt has not been written to the process yet.
uint32 new_prot; // new page protections (when the bpt is active)
bpttype_t type; // breakpoint type
};
// Information about page breakpoints is stored in this data structure.
// The map is indexed by the page start address (not the address specified
// by the user!)
typedef std::map<ea_t, pagebpt_data_t> page_bpts_t; // page_ea -> bpt info
typedef qvector<page_bpts_t::iterator> pbpt_iterators_t; // list of iterators into page_bpts_t
//--------------------------------------------------------------------------
// set of addresses
typedef std::set<ea_t> easet_t;
//-------------------------------------------------------------------------
class idc_value_t;
class rpc_engine_t;
error_t idaapi idc_get_reg_value(idc_value_t *argv, idc_value_t *r);
error_t idaapi idc_set_reg_value(idc_value_t *argv, idc_value_t *r);
void report_idc_error(rpc_engine_t *rpc, ea_t ea, error_t code, ssize_t errval, const char *errprm);
// IDC function name that is exported by a debugger module
// to allow scripts to send debugger commands
#define IDC_SENDDBG_CMD "send_dbg_command"
#define IDC_READ_MSR "read_msr"
#define IDC_WRITE_MSR "write_msr"
#define IDC_STEP_BACK "step_back"
#define IDC_SET_TEV "set_current_tev"
#define IDC_GET_TEV "get_current_tev"
// A macro to convert a pointer to ea_t without sign extension.
#define EA_T(ptr) (ea_t)(size_t)(ptr)
//--------------------------------------------------------------------------
//-V:debmod_bpt_t:730 not all members of a class are initialized inside the constructor: saved
struct debmod_bpt_t
{
ea_t ea;
uchar saved[8]; // size of the biggest supported bpt size (PPC64)
uchar nsaved;
int bid; // (epoc) breakpoint id (from TRK)
debmod_bpt_t() : ea(BADADDR), nsaved(0), bid(0) {}
debmod_bpt_t(ea_t _ea, uchar _nsaved) : ea(_ea), nsaved(_nsaved), bid(0) { QASSERT(1796, nsaved < sizeof(saved)); }
};
typedef std::map<ea_t, debmod_bpt_t> debmodbpt_map_t;
//--------------------------------------------------------------------------
struct eventlist_t : public std::deque<debug_event_t>
{
public:
// save a pending event
void enqueue(const debug_event_t &ev, queue_pos_t pos)
{
if ( pos != IN_BACK )
push_front(ev);
else
push_back(ev);
}
// retrieve a pending event
bool retrieve(debug_event_t *event)
{
if ( empty() )
return false;
// get the first event and return it
*event = front();
pop_front();
return true;
}
};
//--------------------------------------------------------------------------
int send_ioctl(rpc_engine_t *rpc, int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize);
int send_debug_names_to_ida(ea_t *addrs, const char *const *names, int qty);
int send_debug_event_to_ida(const debug_event_t *ev, int rqflags);
void set_arm_thumb_modes(ea_t *addrs, int qty);
char *debug_event_str(const debug_event_t *ev, char *buf, size_t bufsize);
char *debug_event_str(const debug_event_t *ev); // returns static buf
//--------------------------------------------------------------------------
// describes a dll to be imported
struct import_request_t
{
ea_t base;
qstring path;
bytevec_t uuid;
import_request_t(ea_t _base, const qstring &_path, const bytevec_t &_uuid)
: base(_base), path(_path), uuid(_uuid) {}
};
DECLARE_TYPE_AS_MOVABLE(import_request_t);
typedef qvector<import_request_t> import_infos_t;
int import_dll(const import_request_t &req);
//--------------------------------------------------------------------------
struct regctx_t;
//--------------------------------------------------------------------------
struct regctx_entry_t
{
enum type_t
{
IVAL = 0,
FVAL = 1,
DATA = 2,
FUNC = 3,
} type;
int reg_class;
int reg_idx;
union
{
struct
{
size_t offset_in_ctx;
size_t size_in_ctx;
size_t reg_size;
};
struct
{
void (*read_func)(const regctx_t *, regval_t *, void *);
void (*write_func)(regctx_t *, const regval_t *, void *);
void *user_data;
};
};
uint64_t truncate_ival(uint64_t ival) const
{
switch ( reg_size )
{
case 1: ival = uint8_t(ival); break;
case 2: ival = uint16_t(ival); break;
case 4: ival = uint32_t(ival); break;
}
return ival;
}
void read(regval_t *value, const uint8_t *ptr) const
{
if ( type == regctx_entry_t::FUNC )
{
read_func((regctx_t *) ptr, value, user_data);
}
else
{
const uint8_t *p = ptr + offset_in_ctx;
switch ( type )
{
case regctx_entry_t::IVAL:
{
uint64_t ival = 0;
switch ( size_in_ctx )
{
case 1: ival = *(uint8_t *)p; break;
case 2: ival = *(uint16_t *)p; break;
case 4: ival = *(uint32_t *)p; break;
case 8: ival = *(uint64_t *)p; break;
}
ival = truncate_ival(ival);
value->ival = ival;
}
break;
case regctx_entry_t::FVAL:
// TODO: for x86, the value is converted to IEEE format in
// x86_read_registers(). clean this up somehow.
memcpy(value->fval, p, size_in_ctx);
value->rvtype = RVT_FLOAT;
break;
case regctx_entry_t::DATA:
value->set_bytes(p, size_in_ctx);
break;
case regctx_entry_t::FUNC:
// never happens; makes compiler happy.
break;
}
}
}
bool patch(uint8_t *ptr, const regval_t *value) const
{
if ( type == regctx_entry_t::FUNC )
{
write_func((regctx_t *) ptr, value, user_data);
}
else
{
uint8_t *p = ptr + offset_in_ctx;
switch ( type )
{
case regctx_entry_t::IVAL:
{
uint64_t ival = value->ival;
ival = truncate_ival(ival);
switch ( size_in_ctx )
{
case 1: *(uint8_t *)p = ival; break;
case 2: *(uint16_t *)p = ival; break;
case 4: *(uint32_t *)p = ival; break;
case 8: *(uint64_t *)p = ival; break;
}
}
break;
case regctx_entry_t::FVAL:
// TODO: for x86, the value is converted from IEEE format in
// x86_write_register(). clean this up somehow.
memcpy(p, value->fval, size_in_ctx);
break;
case regctx_entry_t::DATA:
if ( value->get_data_size() != size_in_ctx )
return false;
memcpy(p, value->get_data(), value->get_data_size());
break;
case regctx_entry_t::FUNC:
// never happens; makes compiler happy.
break;
}
}
return true;
}
};
DECLARE_TYPE_AS_MOVABLE(regctx_entry_t);
typedef qvector<regctx_entry_t> reg_ctx_entries_t;
//--------------------------------------------------------------------------
struct regctx_base_t
{
dynamic_register_set_t &idaregs; // linked to debmod_t's variable of the same name
thid_t tid;
int clsmask;
reg_ctx_entries_t entries;
void setup(thid_t _tid, int _clsmask=0)
{
tid = _tid;
clsmask = _clsmask;
}
void setup_reg(int dyn_reg_idx)
{
clsmask |= entries[dyn_reg_idx].reg_class;
}
regctx_base_t(dynamic_register_set_t &_idaregs)
: idaregs(_idaregs)
{
setup(0, 0);
}
void add_idareg(register_info_t &ri)
{
idaregs.add_register(ri.name,
ri.flags,
ri.dtype,
ri.register_class,
ri.bit_strings,
ri.default_bit_strings_mask);
}
size_t add_entry(
regctx_entry_t::type_t type,
register_info_t &ri,
size_t offset_in_ctx,
size_t size_in_ctx,
size_t reg_size)
{
size_t dyn_reg_idx = entries.size();
regctx_entry_t &entry = entries.push_back();
entry.type = type;
entry.reg_class = ri.register_class;
entry.reg_idx = dyn_reg_idx;
entry.offset_in_ctx = offset_in_ctx;
entry.size_in_ctx = size_in_ctx;
entry.reg_size = reg_size;
add_idareg(ri);
return dyn_reg_idx;
}
size_t add_ival(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
{
QASSERT(1797, size_in_ctx <= sizeof(regval_t::ival));
size_t reg_size = ri.dtype == dt_word ? 2
: ri.dtype == dt_dword ? 4
: ri.dtype == dt_qword ? 8
: 0;
QASSERT(1798, reg_size != 0);
return add_entry(regctx_entry_t::IVAL, ri, offset_in_ctx, size_in_ctx, reg_size);
}
size_t add_fval(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
{
QASSERT(1799, size_in_ctx <= sizeof(regval_t::fval));
return add_entry(regctx_entry_t::FVAL, ri, offset_in_ctx, size_in_ctx, size_in_ctx);
}
size_t add_data(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
{
return add_entry(regctx_entry_t::DATA, ri, offset_in_ctx, size_in_ctx, size_in_ctx);
}
size_t add_func(
register_info_t &ri,
void (*read_func)(const regctx_t *, regval_t *, void *),
void (*write_func)(regctx_t *, const regval_t *, void *),
void *user_data=nullptr)
{
size_t dyn_reg_idx = entries.size();
regctx_entry_t &entry = entries.push_back();
entry.type = regctx_entry_t::FUNC;
entry.reg_class = ri.register_class;
entry.reg_idx = dyn_reg_idx;
entry.read_func = read_func;
entry.write_func = write_func;
entry.user_data = user_data;
add_idareg(ri);
return dyn_reg_idx;
}
void read_all(regval_t *values)
{
for ( const regctx_entry_t &entry: entries )
if ( (clsmask & entry.reg_class) != 0 )
entry.read(&values[entry.reg_idx], (const uint8_t *) this);
}
bool patch(int dyn_reg_idx, const regval_t *value)
{
return entries[dyn_reg_idx].patch((uint8_t *) this, value);
}
};
//--------------------------------------------------------------------------
// Main class to represent a debugger module
class debmod_t
{
protected:
// processor_t &ph;
typedef std::map<int, regval_t> regval_map_t;
qvector<exception_info_t> exceptions;
name_info_t dn_names;
// Pending events. currently used only to store
// exceptions that happen while attaching
eventlist_t events;
// The last event received via a successful get_debug_event()
debug_event_t last_event;
// debugged process attributes (may be changed after process start/attach)
debapp_attrs_t debapp_attrs;
procvec_t proclist;
// appcall contexts
struct call_context_t
{
regvals_t saved_regs;
ea_t sp;
ea_t ctrl_ea;
bool regs_spoiled;
call_context_t() : sp(BADADDR), ctrl_ea(BADADDR), regs_spoiled(false) {}
};
typedef qstack<call_context_t> call_contexts_t;
typedef std::map<thid_t, call_contexts_t> appcalls_t;
appcalls_t appcalls;
int send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize)
{
return ::send_ioctl(rpc, fn, buf, size, poutbuf, poutsize);
}
// If an IDC error occurs: we cannot prepare an error message on the server
// side because we do not have access to error strings (they are in ida.hlp).
// We pass the error code to IDA (with eventual arguments) so it can prepare
// a nice error message for the user
void report_idc_error(ea_t ea, error_t code, ssize_t errval, const char *errprm)
{
return ::report_idc_error(rpc, ea, code, errval, errprm);
}
typedef std::map<ea_t, lowcnd_t> lowcnds_t;
lowcnds_t cndmap;
eavec_t handling_lowcnds;
bool evaluate_and_handle_lowcnd(debug_event_t *event, int elc_flags=0);
bool handle_lowcnd(lowcnd_t *lc, debug_event_t *event, int elc_flags);
#define ELC_KEEP_EIP 0x0001 // do not reset eip before stepping
#define ELC_KEEP_SUSP 0x0002 // keep suspended state, do not resume after stepping
// helper functions for programmatical single stepping
virtual drc_t dbg_perform_single_step(debug_event_t *event, const insn_t &ins);
virtual int dbg_freeze_threads_except(thid_t) { return 0; }
virtual int dbg_thaw_threads_except(thid_t) { return 0; }
drc_t resume_app_and_get_event(debug_event_t *dev);
void set_platform(const char *platform_name);
// return number of processes, -1 - not implemented
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf);
public:
// initialized by dbg_init()
int debugger_flags;
meminfo_vec_t old_ranges;
rpc_engine_t *rpc;
bool debug_debugger;
// Is dynamic library?
bool is_dll;
// indexes of sp and program counter registers.
// Must be initialized by derived classes.
int sp_idx;
int pc_idx;
// index of frame pointer register
int fp_idx;
// Total number of registers.
// Must be initialized by derived classes.
int nregs;
// Breakpoint code.
// Must be initialized by derived classes.
bytevec_t bpt_code;
qstring input_file_path;
page_bpts_t page_bpts;
// will either send as msg/warning/error through callui,
// or through 'rpc' if it is present.
DEFINE_ALL_NOTIFICATION_FUNCTIONS(rpc);
AS_PRINTF(3,0) static ssize_t dvnotif(int code, rpc_engine_t *rpc, const char *format, va_list va);
bool broken_connection;
pid_t pid;
debmodbpt_map_t bpts;
update_bpt_vec_t deleted_bpts; // deleted bpts in the last update_bpts() call
// if bpt EA was deleted then bpt raised in the same place for the
// same thread does not belong to IDA
bool is_ida_bpt(ea_t ea, thid_t tid)
{
if ( bpts.find(ea) != bpts.end() )
return true;
update_bpt_info_t b;
b.ea = ea;
return deleted_bpts.find(b) != deleted_bpts.end()
&& (last_event.eid() != BREAKPOINT
|| last_event.ea != ea
|| last_event.tid != tid);
}
static bool reuse_broken_connections;
//------------------------------------
// Dynamic register set for debugger_t
//------------------------------------
dynamic_register_set_t idaregs;
//------------------------------------
// Constructors and destructors
//------------------------------------
debmod_t();
virtual ~debmod_t() { cleanup(); }
//------------------------------------
// Debug names methods
//------------------------------------
void clear_debug_names();
name_info_t *get_debug_names();
void save_debug_name(ea_t ea, const char *name);
int set_debug_names();
int send_debug_names_to_ida(ea_t *addrs, const char *const *names, int qty);
int send_debug_event_to_ida(const debug_event_t *ev, int rqflags);
ea_t find_debug_name(const char *name) const;
//------------------------------------
// Utility methods
//------------------------------------
void cleanup(void);
AS_PRINTF(2, 3) void debdeb(const char *format, ...);
AS_PRINTF(2, 3) bool deberr(const char *format, ...);
bool same_as_oldmemcfg(const meminfo_vec_t &ranges) const;
void save_oldmemcfg(const meminfo_vec_t &ranges);
bool continue_after_last_event(bool handled = true);
lowcnd_t *get_failed_lowcnd(thid_t tid, ea_t ea);
page_bpts_t::iterator find_page_bpt(ea_t ea, int size=1);
bool del_page_bpt(ea_t ea, bpttype_t type);
void enable_page_bpts(bool enable);
ea_t calc_page_base(ea_t ea) { return align_down(ea, dbg_memory_page_size()); }
void log_exception(const debug_event_t *ev, const exception_info_t *ei);
uint64 probe_file_size(int fn, uint64 step);
void set_input_path(const char *input_path);
int read_bpt_orgbytes(bytevec_t *buf, ea_t ea, int len);
//------------------------------------
// Shared methods
//------------------------------------
virtual bool check_input_file_crc32(uint32 orig_crc);
virtual const exception_info_t *find_exception(int code);
virtual bool get_exception_name(int code, char *buf, size_t bufsize);
virtual drc_t idaapi dbg_get_processes(procinfo_vec_t *info, qstring *errbuf);
//------------------------------------
// Methods to be implemented
//------------------------------------
virtual void idaapi dbg_set_debugging(bool _debug_debugger) = 0;
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) = 0;
virtual void idaapi dbg_term(void) = 0;
virtual drc_t idaapi dbg_detach_process(void) = 0;
virtual drc_t idaapi dbg_start_process(
const char *path,
const char *args,
const char *startdir,
int flags,
const char *input_path,
uint32 input_file_crc32,
qstring *errbuf) = 0;
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_msecs) = 0;
virtual drc_t idaapi dbg_attach_process(pid_t process_id, int event_id, int flags, qstring *errbuf) = 0;
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) = 0;
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) = 0;
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) = 0;
virtual void idaapi dbg_set_exception_info(const exception_info_t *info, int qty);
virtual void idaapi dbg_stopped_at_debug_event(import_infos_t *infos, bool dlls_added, thread_name_vec_t *thr_names) = 0;
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) = 0;
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) = 0;
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) = 0;
virtual drc_t idaapi dbg_read_registers(
thid_t thread_id,
int clsmask,
regval_t *values,
qstring *errbuf) = 0;
virtual drc_t idaapi dbg_write_register(
thid_t thread_id,
int reg_idx,
const regval_t *value,
qstring *errbuf) = 0;
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) = 0;
virtual ea_t idaapi map_address(ea_t ea, const regval_t *, int /* regnum */) { return ea; }
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &ranges, qstring *errbuf) = 0;
virtual int idaapi dbg_get_scattered_image(scattered_image_t & /*si*/, ea_t /*base*/) { return -1; }
virtual bool idaapi dbg_get_image_uuid(bytevec_t * /*uuid*/, ea_t /*base*/) { return false; }
virtual ea_t idaapi dbg_get_segm_start(ea_t /*base*/, const qstring & /*segname*/) { return BADADDR; }
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) = 0;
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) = 0;
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) = 0;
// for swbpts, len may be -1 (unknown size, for example arm/thumb mode) or bpt opcode length
// dbg_add_bpt returns 2 if it adds a page bpt
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) = 0;
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) = 0;
virtual drc_t idaapi dbg_update_bpts(int *nbpts, update_bpt_info_t *bpts, int nadd, int ndel, qstring *errbuf);
virtual int idaapi dbg_add_page_bpt(bpttype_t /*type*/, ea_t /*ea*/, int /*size*/) { return 0; }
virtual bool idaapi dbg_enable_page_bpt(page_bpts_t::iterator /*p*/, bool /*enable*/) { return false; }
virtual drc_t idaapi dbg_update_lowcnds(int *nupdated, const lowcnd_t *lowcnds, int nlowcnds, qstring *errbuf);
virtual drc_t idaapi dbg_eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf);
virtual int idaapi dbg_open_file(const char * /*file*/, uint64 * /*fsize*/, bool /*readonly*/) { return -1; }
virtual void idaapi dbg_close_file(int /*fn*/) {}
virtual ssize_t idaapi dbg_read_file(int /*fn*/, qoff64_t /*off*/, void * /*buf*/, size_t /*size*/) { return 0; }
virtual ssize_t idaapi dbg_write_file(int /*fn*/, qoff64_t /*off*/, const void * /*buf*/, size_t /*size*/) { return 0; }
virtual int idaapi handle_ioctl(
int /*fn*/,
const void * /*buf*/,
size_t /*size*/,
void ** /*outbuf*/,
ssize_t * /*outsize*/)
{
return 0;
}
virtual int idaapi get_system_specific_errno(void) const; // this code must be acceptable by winerr()
virtual drc_t idaapi dbg_update_call_stack(thid_t, call_stack_t *) { return DRC_NONE; }
virtual ea_t idaapi dbg_appcall(
ea_t /*func_ea*/,
thid_t /*tid*/,
int /*stkarg_nbytes*/,
const struct regobjs_t * /*regargs*/,
struct relobj_t * /*stkargs*/,
struct regobjs_t * /*retregs*/,
qstring *errbuf,
debug_event_t * /*event*/,
int /*flags*/);
virtual drc_t idaapi dbg_cleanup_appcall(thid_t /*tid*/);
virtual bool idaapi write_registers(
thid_t /*tid*/,
int /*start*/,
int /*count*/,
const regval_t * /*values*/)
{
return false;
}
// finalize appcall stack image
// input: stack image contains the return address at the beginning
virtual int finalize_appcall_stack(call_context_t &, regval_map_t &, bytevec_t &) { return 0; }
virtual ea_t calc_appcall_stack(const regvals_t &regvals);
virtual bool should_stop_appcall(thid_t tid, const debug_event_t *event, ea_t ea);
virtual bool should_suspend_at_exception(const debug_event_t *event, const exception_info_t *ei);
virtual bool preprocess_appcall_cleanup(thid_t, call_context_t &) { return true; }
virtual int get_regidx(const char *regname, int *clsmask) = 0;
virtual uint32 dbg_memory_page_size(void) { return 0x1000; }
virtual bool idaapi dbg_prepare_broken_connection(void) { return false; }
virtual bool idaapi dbg_continue_broken_connection(pid_t) { old_ranges.clear(); return true; }
virtual bool idaapi dbg_enable_trace(thid_t, bool, int) { return false; }
virtual bool idaapi dbg_is_tracing_enabled(thid_t, int) { return false; }
virtual int idaapi dbg_rexec(const char *cmdline);
virtual void adjust_swbpt(ea_t *, int *) {};
virtual void dbg_get_debapp_attrs(debapp_attrs_t *out_pattrs) const;
virtual bool idaapi dbg_get_srcinfo_path(qstring * /*path*/, ea_t /*base*/) const { return false; }
virtual bool import_dll(const import_request_t & /*req*/) { return false; }
virtual drc_t idaapi dbg_bin_search(
ea_t *ea,
ea_t start_ea,
ea_t end_ea,
const compiled_binpat_vec_t &ptns,
int srch_flags,
qstring *errbuf);
bool restore_broken_breakpoints(void);
void set_addr_size(int size) { debapp_attrs.addrsize = size; }
void set_endianness(bool is_be) { debapp_attrs.is_be = is_be; }
};
//---------------------------------------------------------------------------
//
// Some functions, per OS implemented
//
bool init_subsystem();
bool term_subsystem();
debmod_t *create_debug_session(void *params);
//
// Processor specific init/term
//
void processor_specific_init(void);
void processor_specific_term(void);
// Perform an action on all existing debugger modules
struct debmod_visitor_t
{
virtual int visit(debmod_t *debmod) = 0;
};
int for_all_debuggers(debmod_visitor_t &v);
//
// Utility functions
//
// Common method between MacOS and Linux to launch a process
drc_t idaapi maclnx_launch_process(
debmod_t *debmod,
const char *path,
const char *args,
const char *startdir,
int flags,
const char *input_path,
uint32 input_file_crc32,
void **child_pid,
qstring *errbuf);
bool add_idc_funcs(const struct ext_idcfunc_t funcs[], size_t nfuncs, bool reg);
//
// Externs
//
extern debmod_t *idc_debmod;
extern thid_t idc_thread;
extern bool ignore_sigint;
//---------------------------------------------------------------------------
// server.cpp
bool lock_begin();
bool lock_end();
// bool srv_lock_begin(void);
// bool srv_lock_end(void);
#endif

292
idasdk75/dbg/exceptions.cfg Normal file
View File

@@ -0,0 +1,292 @@
; This file describes the exception definitions.
; The definitions will be used for new databases.
; for each exception:
; code stop_at pass_to_app notification name description
;
; code is the exception code
; stop_at is one of stop or nostop - should the debugger suspend
; the process when the exception occurs
; pass_to_app is one of app or mask - should the debugger pass
; the exception to the application or not
; notification is one of warn/log/silent
; name is the exception short name
; description is the exception description displayed to the user
; Windows exceptions
.win32,bochs_win32
0xC0000005 stop mask warn EXCEPTION_ACCESS_VIOLATION The instruction at 0x%a referenced memory at 0x%a. The memory could not be %s
0x80000002 stop mask warn EXCEPTION_DATATYPE_MISALIGNMENT A datatype misalignment error was detected in a load or store instruction
0x80000003 stop mask warn EXCEPTION_BREAKPOINT Software breakpoint exception
0x80000004 stop mask warn EXCEPTION_SINGLE_STEP Single step exception
0xC000008C stop mask warn EXCEPTION_ARRAY_BOUNDS_EXCEEDED Array bounds exceeded
0xC000008D stop mask warn EXCEPTION_FLT_DENORMAL_OPERAND Floating point denormal operand
0xC000008E stop mask warn EXCEPTION_FLT_DIVIDE_BY_ZERO Floating point divide by zero
0xC000008F stop mask warn EXCEPTION_FLT_INEXACT_RESULT Floating point inexact result
0xC0000090 stop mask warn EXCEPTION_FLT_INVALID_OPERATION Floating point invalid operation
0xC0000091 stop mask warn EXCEPTION_FLT_OVERFLOW Floating point overflow
0xC0000092 stop mask warn EXCEPTION_FLT_STACK_CHECK Floating point stack check
0xC0000093 stop mask warn EXCEPTION_FLT_UNDERFLOW Floating point underflow
0xC0000094 stop mask warn EXCEPTION_INT_DIVIDE_BY_ZERO Integer divide by zero
0xC0000095 stop mask warn EXCEPTION_INT_OVERFLOW Integer overflow
0xC0000096 stop mask warn EXCEPTION_PRIV_INSTRUCTION Priveleged instruction
0xC0000006 stop mask warn EXCEPTION_IN_PAGE_ERROR The instruction at "0x%a" referenced memory at "0x%a". The required data was not placed into memory because of an I/O error status of "0x%a"
0xC000001D stop mask warn EXCEPTION_ILLEGAL_INSTRUCTION An attempt was made to execute an illegal instruction
0xC0000025 stop mask warn EXCEPTION_NONCONTINUABLE_EXCEPTION Windows cannot continue from this exception
0xC00000FD stop mask warn EXCEPTION_STACK_OVERFLOW A new guard page for the stack cannot be created (stack overflow)
0xC0000026 stop mask warn EXCEPTION_INVALID_DISPOSITION An invalid exception disposition was returned by an exception handler
0x80000001 stop mask warn EXCEPTION_GUARD_PAGE A page of memory that marks the end of a data structure such as a stack or an array has been accessed
0xC0000008 stop mask warn EXCEPTION_INVALID_HANDLE An invalid HANDLE was specified
0xEEFFACE stop mask warn EXCEPTION_BCC_FATAL Fatal unhandled exception in the BCC compiled program
0xEEDFAE6 stop mask warn EXCEPTION_BCC_NORMAL Unhandled exception in the BCC compiled program
0x40010005 stop mask warn DBG_CONTROL_C CTRL+C was input to console process
0x40010008 stop mask warn DBG_CONTROL_BREAK CTRL+BREAK was input to console process
0xE06D7363 stop mask warn EXCEPTION_MSC_CPLUSPLUS Microsoft C++ exception
0xE0434F4D stop mask warn EXCEPTION_MANAGED_NET Managed .NET exception
0xE0434352 stop mask warn EXCEPTION_MANAGED_NET_V4 Managed .NET exception (V4+)
0x4000001E stop mask warn EXCEPTION_WX86_SINGLE_STEP Single step exception (x86 emulation)
0x4000001F stop mask warn EXCEPTION_WX86_BREAKPOINT Software breakpoint exception (x86 emulation)
0x406D1388 nostop mask log MS_VC_EXCEPTION SetThreadName
; Linux exceptions
.linux
1 stop mask warn SIGHUP Hangup
2 stop mask warn SIGINT Interrupt
3 stop mask warn SIGQUIT Quit
4 stop mask warn SIGILL Illegal instruction
5 stop mask warn SIGTRAP Trace trap
6 stop mask warn SIGABRT Abort
7 stop mask warn SIGBUS BUS error
8 stop mask warn SIGFPE Floating-point exception
9 stop mask warn SIGKILL Kill unblockable
10 stop mask warn SIGUSR1 User-defined signal 1
11 stop mask warn SIGSEGV Segmentation violation
12 stop mask warn SIGUSR2 User-defined signal 2
13 stop mask warn SIGPIPE Broken pipe
14 stop mask warn SIGALRM Alarm clock
15 stop mask warn SIGTERM Termination
16 stop mask warn SIGSTKFLT Stack fault
17 stop mask warn SIGCHLD Child status has changed
18 stop mask warn SIGCONT Continue
19 stop mask warn SIGSTOP Stop unblockable
20 stop mask warn SIGTSTP Keyboard stop
21 stop mask warn SIGTTIN Background read from tty
22 stop mask warn SIGTTOU Background write to tty
23 stop mask warn SIGURG Urgent condition on socket
24 stop mask warn SIGXCPU CPU limit exceeded
25 stop mask warn SIGXFSZ File size limit exceeded
26 stop mask warn SIGVTALRM Virtual alarm clock
27 stop mask warn SIGPROF Profiling alarm clock
28 stop mask warn SIGWINCH Window size change
29 stop mask warn SIGIO I/O now possible
30 stop mask warn SIGPWR Power failure restart
31 stop mask warn SIGSYS Bad system call
; Mac OS X/iphone exceptions
.macosx,ios,xnu
1 stop mask warn SIGHUP terminal line hangup
2 stop mask warn SIGINT interrupt program
3 stop mask warn SIGQUIT quit program
4 stop mask warn SIGILL illegal instruction
5 stop mask warn SIGTRAP trace trap
6 stop mask warn SIGABRT abort program
7 stop mask warn SIGEMT emulate instruction executed
8 stop mask warn SIGFPE floating-point exception
9 stop mask warn SIGKILL kill program
10 stop mask warn SIGBUS bus error
11 stop mask warn SIGSEGV segmentation violation
12 stop mask warn SIGSYS non-existent system call invoked
13 stop mask warn SIGPIPE write on a pipe with no reader
14 stop mask warn SIGALRM real-time timer expired
15 stop mask warn SIGTERM software termination signal
16 stop mask warn SIGURG urgent condition present on socket
17 stop mask warn SIGSTOP stop
18 stop mask warn SIGTSTP stop signal generated from keyboard
19 stop mask warn SIGCONT continue after stop
20 stop mask warn SIGCHLD child status has changed
21 stop mask warn SIGTTIN background read attempted from control terminal
22 stop mask warn SIGTTOU background write attempted to control terminal
23 stop mask warn SIGIO I/O is possible on a descriptor
24 stop mask warn SIGXCPU cpu time limit exceeded
25 stop mask warn SIGXFSZ file size limit exceeded
26 stop mask warn SIGVTALRM virtual time alarm
27 stop mask warn SIGPROF profiling timer alarm
28 stop mask warn SIGWINCH Window size change
29 stop mask warn SIGINFO status request from keyboard
30 stop mask warn SIGUSR1 User defined signal 1
31 stop mask warn SIGUSR2 User defined signal 2
;additional iphone exceptions
145 stop mask warn EXC_BAD_ACCESS Bad memory access
146 stop mask warn EXC_BAD_INSTRUCTION Bad instruction
147 stop mask warn EXC_ARITHMETIC Arithmetic exception
148 stop mask warn EXC_EMULATION Emulation exception
149 stop mask warn EXC_SOFTWARE Software exception
150 stop mask warn EXC_BREAKPOINT Breakpoint exception
; Bochs IA-32 emulator: raw exceptions
; (in addition to MS Windows exceptions defined above)
.bochs_win32
0x00 stop mask warn DIVIDE_BY_ZERO Divide by zero
0x01 stop mask warn SINGLE_STEP Single step
0x03 stop mask warn BREAKPOINT Breakpoint
0x04 stop mask warn INTO Interrupt on overflow
0x06 stop mask warn INVALID_OPCODE Invalid opcode
0x0C stop mask warn STACK_EXCEPTION Stack exception
0x0D stop mask warn GENERAL_PROTECTION_FAULT General protection fault
0x0E stop mask warn PAGE_FAULT Page fault at 0x%a, error code %a
0x10 stop mask warn FLOATING_POINT_ERROR Floating point error
.gdb
; gdb signals
1 stop mask warn SIGHUP Hangup
2 stop mask warn SIGINT Interrupt
3 stop mask warn SIGQUIT Quit
4 stop mask warn SIGILL Illegal instruction
5 stop mask warn SIGTRAP Trace/breakpoint trap
6 stop mask warn SIGABRT Aborted
7 stop mask warn SIGEMT Emulation trap
8 stop mask warn SIGFPE Arithmetic exception
9 stop mask warn SIGKILL Killed
10 stop mask warn SIGBUS Bus error
11 stop mask warn SIGSEGV Segmentation fault
12 stop mask warn SIGSYS Bad system call
13 stop mask warn SIGPIPE Broken pipe
14 stop mask warn SIGALRM Alarm clock
15 stop mask warn SIGTERM Terminated
16 stop mask warn SIGURG Urgent I/O condition
17 stop mask warn SIGSTOP Stopped (signal)
18 stop mask warn SIGTSTP Stopped (user)
19 stop mask warn SIGCONT Continued
20 stop mask warn SIGCHLD Child status changed
21 stop mask warn SIGTTIN Stopped (tty input)
22 stop mask warn SIGTTOU Stopped (tty output)
23 stop mask warn SIGIO I/O possible
24 stop mask warn SIGXCPU CPU time limit exceeded
25 stop mask warn SIGXFSZ File size limit exceeded
26 stop mask warn SIGVTALRM Virtual timer expired
27 stop mask warn SIGPROF Profiling timer expired
28 stop mask warn SIGWINCH Window size changed
29 stop mask warn SIGLOST Resource lost
30 stop mask warn SIGUSR1 User defined signal 1
31 stop mask warn SIGUSR2 User defined signal 2
32 stop mask warn SIGPWR Power fail/restart
33 stop mask warn SIGPOLL Pollable event occurred
34 stop mask warn SIGWIND SIGWIND
35 stop mask warn SIGPHONE SIGPHONE
36 stop mask warn SIGWAITING Process's LWPs are blocked
37 stop mask warn SIGLWP Signal LWP
38 stop mask warn SIGDANGER Swap space dangerously low
39 stop mask warn SIGGRANT Monitor mode granted
40 stop mask warn SIGRETRACT Need to relinquish monitor mode
41 stop mask warn SIGMSG Monitor mode data available
42 stop mask warn SIGSOUND Sound completed
43 stop mask warn SIGSAK Secure attention
44 stop mask warn SIGPRIO SIGPRIO
45 stop mask warn SIG33 Real-time event 33
46 stop mask warn SIG34 Real-time event 34
47 stop mask warn SIG35 Real-time event 35
48 stop mask warn SIG36 Real-time event 36
49 stop mask warn SIG37 Real-time event 37
50 stop mask warn SIG38 Real-time event 38
51 stop mask warn SIG39 Real-time event 39
52 stop mask warn SIG40 Real-time event 40
53 stop mask warn SIG41 Real-time event 41
54 stop mask warn SIG42 Real-time event 42
55 stop mask warn SIG43 Real-time event 43
56 stop mask warn SIG44 Real-time event 44
57 stop mask warn SIG45 Real-time event 45
58 stop mask warn SIG46 Real-time event 46
59 stop mask warn SIG47 Real-time event 47
60 stop mask warn SIG48 Real-time event 48
61 stop mask warn SIG49 Real-time event 49
62 stop mask warn SIG50 Real-time event 50
63 stop mask warn SIG51 Real-time event 51
64 stop mask warn SIG52 Real-time event 52
65 stop mask warn SIG53 Real-time event 53
66 stop mask warn SIG54 Real-time event 54
67 stop mask warn SIG55 Real-time event 55
68 stop mask warn SIG56 Real-time event 56
69 stop mask warn SIG57 Real-time event 57
70 stop mask warn SIG58 Real-time event 58
71 stop mask warn SIG59 Real-time event 59
72 stop mask warn SIG60 Real-time event 60
73 stop mask warn SIG61 Real-time event 61
74 stop mask warn SIG62 Real-time event 62
75 stop mask warn SIG63 Real-time event 63
76 stop mask warn SIGCANCEL LWP internal signal
77 stop mask warn SIG32 Real-time event 32
78 stop mask warn SIG64 Real-time event 64
79 stop mask warn SIG65 Real-time event 65
80 stop mask warn SIG66 Real-time event 66
81 stop mask warn SIG67 Real-time event 67
82 stop mask warn SIG68 Real-time event 68
83 stop mask warn SIG69 Real-time event 69
84 stop mask warn SIG70 Real-time event 70
85 stop mask warn SIG71 Real-time event 71
86 stop mask warn SIG72 Real-time event 72
87 stop mask warn SIG73 Real-time event 73
88 stop mask warn SIG74 Real-time event 74
89 stop mask warn SIG75 Real-time event 75
90 stop mask warn SIG76 Real-time event 76
91 stop mask warn SIG77 Real-time event 77
92 stop mask warn SIG78 Real-time event 78
93 stop mask warn SIG79 Real-time event 79
94 stop mask warn SIG80 Real-time event 80
95 stop mask warn SIG81 Real-time event 81
96 stop mask warn SIG82 Real-time event 82
97 stop mask warn SIG83 Real-time event 83
98 stop mask warn SIG84 Real-time event 84
99 stop mask warn SIG85 Real-time event 85
100 stop mask warn SIG86 Real-time event 86
101 stop mask warn SIG87 Real-time event 87
102 stop mask warn SIG88 Real-time event 88
103 stop mask warn SIG89 Real-time event 89
104 stop mask warn SIG90 Real-time event 90
105 stop mask warn SIG91 Real-time event 91
106 stop mask warn SIG92 Real-time event 92
107 stop mask warn SIG93 Real-time event 93
108 stop mask warn SIG94 Real-time event 94
109 stop mask warn SIG95 Real-time event 95
110 stop mask warn SIG96 Real-time event 96
111 stop mask warn SIG97 Real-time event 97
112 stop mask warn SIG98 Real-time event 98
113 stop mask warn SIG99 Real-time event 99
114 stop mask warn SIG100 Real-time event 100
115 stop mask warn SIG101 Real-time event 101
116 stop mask warn SIG102 Real-time event 102
117 stop mask warn SIG103 Real-time event 103
118 stop mask warn SIG104 Real-time event 104
119 stop mask warn SIG105 Real-time event 105
120 stop mask warn SIG106 Real-time event 106
121 stop mask warn SIG107 Real-time event 107
122 stop mask warn SIG108 Real-time event 108
123 stop mask warn SIG109 Real-time event 109
124 stop mask warn SIG110 Real-time event 110
125 stop mask warn SIG111 Real-time event 111
126 stop mask warn SIG112 Real-time event 112
127 stop mask warn SIG113 Real-time event 113
128 stop mask warn SIG114 Real-time event 114
129 stop mask warn SIG115 Real-time event 115
130 stop mask warn SIG116 Real-time event 116
131 stop mask warn SIG117 Real-time event 117
132 stop mask warn SIG118 Real-time event 118
133 stop mask warn SIG119 Real-time event 119
134 stop mask warn SIG120 Real-time event 120
135 stop mask warn SIG121 Real-time event 121
136 stop mask warn SIG122 Real-time event 122
137 stop mask warn SIG123 Real-time event 123
138 stop mask warn SIG124 Real-time event 124
139 stop mask warn SIG125 Real-time event 125
140 stop mask warn SIG126 Real-time event 126
141 stop mask warn SIG127 Real-time event 127
142 stop mask warn SIGINFO Information request
145 stop mask warn EXC_BAD_ACCESS Could not access memory
146 stop mask warn EXC_BAD_INSTRUCTION Illegal instruction/operand
147 stop mask warn EXC_ARITHMETIC Arithmetic exception
148 stop mask warn EXC_EMULATION Emulation instruction
149 stop mask warn EXC_SOFTWARE Software generated exception
150 stop mask warn EXC_BREAKPOINT Breakpoint
151 stop mask warn SIGLIBRT librt internal signal
.dalvik
1 nostop mask warn java.lang.Throwable The superclass of all errors and exceptions in the Java language

View File

@@ -0,0 +1,88 @@
/*
Android specific functions.
*/
// r_brk():
// B0003050 70 47 BX LR
static const uchar bxlr_thumb[] = { 0x70, 0x47 };
#define LINKER "/system/bin/linker"
//--------------------------------------------------------------------------
// on android /system/bin/linker comes without any symbols.
// Since there is no other way, we scan the data segment for
// dcd 1, ?, r_brk, 0, 0
// r_debug is located very close to the beginning of the data segment,
// we should find it fine. In any case, we check only the first 4KB.
bool linux_debmod_t::add_android_shlib_bpt(const meminfo_vec_t &miv, bool attaching)
{
// find read/writable linker memory range
meminfo_vec_t::const_iterator p;
ea_t linker_base = BADADDR;
for ( p=miv.begin(); p != miv.end(); ++p )
{
if ( p->name == LINKER )
{
if ( linker_base == BADADDR )
linker_base = p->start_ea;
// assume the data segment to be readable and writable
if ( (p->perm & 6) == 6 )
break;
}
}
if ( p == miv.end() )
{
msg("Failed to find data segment of " LINKER "\n");
return false;
}
// read max 2KB
uint32 buf[2048];
int nbytes = qmin(p->size(), sizeof(buf));
ea_t dataseg = p->start_ea;
nbytes = dbg_read_memory(dataseg, buf, nbytes, NULL);
uint32 *ptr = buf;
for ( int i=0; i < nbytes/4-5; i++, ptr++ )
{
if ( ptr[0] == 1 // version
&& (attaching || ptr[1] == 0) // r_map, 0 at the beginning
&& (ptr[2] & 1) != 0 && ptr[2] < dataseg // r_brk (Thumb pointer)
&& (attaching || ptr[3] == 0) // r_state: RT_CONSISTENT
&& ptr[4] == 0 ) // linker baseaddr: always zero?
{
ea_t r_brk = ptr[2] & ~1;
// check if linker is not relocated yet
if ( r_brk < linker_base )
r_brk += linker_base; // adjust address
uchar opcode[2];
if ( dbg_read_memory(r_brk, opcode, 2, NULL) == 2
&& memcmp(opcode, bxlr_thumb, 2) == 0 )
{
// found it!
if ( add_internal_bp(shlib_bpt, r_brk+1) )
{
dmsg("found r_debug (r_brk=%a)\n", r_brk);
return true;
}
}
}
}
msg("Failed to find r_debug in " LINKER "\n");
return false;
}
//--------------------------------------------------------------------------
// Android reports shared objects without any path. Try to find full path.
void linux_debmod_t::make_android_abspath(qstring *in_out_path)
{
if ( qisabspath(in_out_path->c_str()) )
return;
// Apparently /proc didn't return an absolute path. Check /system/lib.
// Normally we should not arrive here, this is just for safety.
char path[QMAXPATH];
qmakepath(path, sizeof(path), "/system/lib", in_out_path->c_str(), NULL);
if ( qfileexist(path) )
*in_out_path = path;
}

View File

@@ -0,0 +1,63 @@
/*
Android specific definitions
*/
#ifndef __ANDROID_HPP
#define __ANDROID_HPP
// Android NDK lacks link.h, so we have to use our own definitions
#include <android/api-level.h>
#include "dbg_rpc_handler.h"
struct link_map
{
uintptr_t l_addr;
char * l_name;
uintptr_t l_ld;
struct link_map * l_next;
struct link_map * l_prev;
};
struct r_debug
{
int32_t r_version;
struct link_map * r_map;
int32_t r_brk;
// Values for r_state
enum
{
RT_CONSISTENT,
RT_ADD,
RT_DELETE
};
int32_t r_state;
uintptr_t r_ldbase;
};
// pread64 is missing
#define pread64 pread
// thread_db.h lacks many definitions as well:
#define TD_MIN_EVENT_NUM 0
#define TD_MAX_EVENT_NUM 16
#define td_eventismember(set, n) (((set)->events & (1 << (n))) != 0)
typedef void *prgregset_t;
typedef void *prfpregset_t;
typedef int td_thr_type_e;
extern "C"
{
inline td_err_e td_init(void) { return TD_OK; }
inline td_err_e td_thr_set_event(const td_thrhandle_t *, td_thr_events_t *) { return TD_OK; }
inline td_err_e td_thr_setsigpending(const td_thrhandle_t *, unsigned char, const sigset_t *) { return TD_OK; }
}
// Other missing definitions:
typedef int32 __ptrace_request;
#define user_regs pt_regs
#endif // define __ANDROID_HPP

View File

@@ -0,0 +1,35 @@
#define REMOTE_DEBUGGER
#define RPC_CLIENT
static const char wanted_name[] = "Remote ARM Linux/Android debugger";
#define DEBUGGER_NAME "armlinux"
#define PROCESSOR_NAME "arm"
#define DEFAULT_PLATFORM_NAME "linux"
#define TARGET_PROCESSOR PLFM_ARM
#define DEBUGGER_ID DEBUGGER_ID_ARM_LINUX_USER
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
| DBG_FLAG_SMALLBLKS \
| DBG_FLAG_LOWCNDS \
| DBG_FLAG_DEBTHREAD \
| DBG_FLAG_PREFER_SWBPTS)
#define HAVE_APPCALL
#define S_FILETYPE f_ELF
#include <pro.h>
#include <idp.hpp>
#include <idd.hpp>
#include <ua.hpp>
#include <range.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <network.hpp>
#include "dbg_rpc_client.h"
#include "rpc_debmod.h"
rpc_debmod_t g_dbgmod(DEFAULT_PLATFORM_NAME);
#include "common_stub_impl.cpp"
#include "arm_local_impl.cpp"
#include "linux_local_impl.cpp"
#include "common_local_impl.cpp"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,349 @@
#ifndef __LINUX_DEBUGGER_MODULE__
#define __LINUX_DEBUGGER_MODULE__
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/user.h>
#include "linuxbase_debmod.h"
extern "C"
{
#include <thread_db.h>
}
#include <map>
#include <deque>
typedef int HANDLE;
typedef uint32 DWORD;
#define INVALID_HANDLE_VALUE (-1)
using std::pair;
using std::make_pair;
//--------------------------------------------------------------------------
typedef std::map<ea_t, qstring> ea2name_t;
typedef std::map<qstring, ea_t> name2ea_t;
#ifndef WCONTINUED
#define WCONTINUED 8
#endif
#ifndef __WALL
#define __WALL 0x40000000
#endif
//--------------------------------------------------------------------------
// image information
struct image_info_t
{
image_info_t() : base(BADADDR), size(0), dl_crc(0) {}
image_info_t(
ea_t _base,
asize_t _size,
const qstring &_fname,
const qstring &_soname)
: base(_base), size(_size), fname(_fname), soname(_soname), dl_crc(0) {}
ea_t base;
asize_t size; // image size, currently 0
qstring fname;
qstring soname;
ea2name_t names;
qstring buildid;
qstring debuglink;
uint32 dl_crc;
};
typedef std::map<ea_t, image_info_t> images_t; // key: image base address
//--------------------------------------------------------------------------
enum thstate_t
{
RUNNING, // running
STOPPED, // waiting to be resumed after qwait
DYING, // we got a notification that the thread is about to die
DEAD, // dead thread; ignore any signals from it
};
//--------------------------------------------------------------------------
// thread information
struct thread_info_t
{
thread_info_t(int t)
: tid(t), suspend_count(0), user_suspend(0), child_signum(0), single_step(false),
state(STOPPED), waiting_sigstop(false), got_pending_status(false), pending_status(0) {}
int tid;
int suspend_count;
int user_suspend;
int child_signum;
bool single_step;
thstate_t state;
bool waiting_sigstop;
bool got_pending_status;
int pending_status;
qstring name; // thread name
bool is_running(void) const
{
return state == RUNNING && !waiting_sigstop && !got_pending_status;
}
};
//--------------------------------------------------------------------------
typedef std::map<HANDLE, thread_info_t> threads_t; // (tid -> info)
//--------------------------------------------------------------------------
enum ps_err_e
{
PS_OK, /* Success. */
PS_ERR, /* Generic error. */
PS_BADPID, /* Bad process handle. */
PS_BADLID, /* Bad LWP id. */
PS_BADADDR, /* Bad address. */
PS_NOSYM, /* Symbol not found. */
PS_NOFREGS /* FPU register set not available. */
};
struct ps_prochandle
{
pid_t pid;
};
#ifndef UINT32_C
# define UINT32_C uint32
#endif
//--------------------------------------------------------------------------
struct internal_bpt
{
ea_t bpt_addr;
uchar saved[BPT_CODE_SIZE];
uchar nsaved;
internal_bpt(): bpt_addr(0), nsaved(0) {} //-V730 Not all members of a class are initialized
};
//--------------------------------------------------------------------------
struct mapfp_entry_t
{
ea_t ea1;
ea_t ea2;
ea_t offset;
uint64 inode;
char perm[8];
char device[8];
uint8 bitness; // Number of bits in segment addresses (0-16bit, 1-32bit, 2-64bit)
qstring fname;
bool empty(void) const { return ea1 >= ea2; }
};
//--------------------------------------------------------------------------
struct chk_signal_info_t
{
pid_t pid;
int status;
int timeout_ms;
chk_signal_info_t(int _timeout_ms)
{
timeout_ms = _timeout_ms;
pid = 0;
status = 0;
}
};
//--------------------------------------------------------------------------
enum attach_mode_t
{
AMT_NO_ATTACH,
AMT_ATTACH_NORMAL,
AMT_ATTACH_BROKEN
};
//--------------------------------------------------------------------------
class linux_debmod_t: public linuxbase_debmod_t
{
typedef linuxbase_debmod_t inherited;
// thread_db related data and functions:
struct ps_prochandle prochandle;
td_thragent_t *ta;
internal_bpt birth_bpt; //thread created
internal_bpt death_bpt; //thread exited
internal_bpt shlib_bpt; //shared lib list changed
bool complained_shlib_bpt;
void make_android_abspath(qstring *in_out_path);
bool add_android_shlib_bpt(const meminfo_vec_t &miv, bool attaching);
bool add_internal_bp(internal_bpt &bp, ea_t addr);
bool erase_internal_bp(internal_bpt &bp);
bool tdb_enable_event(td_event_e event, internal_bpt *bp);
void tdb_update_threads(void);
bool tdb_new(void);
void tdb_delete(void);
void tdb_handle_messages(int pid);
void dead_thread(int tid, thstate_t state);
void store_pending_signal(int pid, int status);
// procfs
void procfs_collect_threads(void);
bool attach_collected_thread(unsigned long lwp);
bool get_thread_name(qstring *thr_name, thid_t tid);
void update_thread_names(thread_name_vec_t *thr_names);
// list of debug names not yet sent to IDA
name_info_t pending_names;
name_info_t nptl_names;
pid_t check_for_signal(int *status, int pid, int timeout_ms) const;
int find_largest_addrsize(const meminfo_vec_t &miv);
void _import_dll(image_info_t &ii);
void _import_symbols_from_file(name_info_t *out, image_info_t &ii);
public:
easet_t dlls_to_import; // list of dlls to import information from
images_t dlls; // list of loaded DLLs
threads_t threads;
qvector<thid_t> deleted_threads;
qvector<thid_t> seen_threads; // thread was born and appeared too early
// debugged process information
HANDLE process_handle;
HANDLE thread_handle;
bool exited; // Did the process exit?
easet_t removed_bpts; // removed breakpoints
FILE *mapfp; // map file handle
int npending_signals; // number of pending signals
bool may_run;
bool requested_to_suspend;
bool in_event; // IDA kernel is handling a debugger event
qstring interp;
qstring exe_path; // name of the executable file
ea_t nptl_base; // base of 'libpthread.so'
regctx_t *reg_ctx;
linux_debmod_t();
~linux_debmod_t();
void init_reg_ctx(void);
void term_reg_ctx(void);
thread_info_t &add_thread(int tid);
void del_thread(int tid);
thread_info_t *get_thread(thid_t tid);
bool retrieve_pending_signal(pid_t *pid, int *status);
int get_debug_event(debug_event_t *event, int timeout_ms);
bool del_pending_event(event_id_t id, const char *module_name);
void enqueue_event(const debug_event_t &ev, queue_pos_t pos);
bool suspend_all_threads(void);
bool resume_all_threads(void);
int dbg_freeze_threads(thid_t tid, bool exclude=true);
int dbg_thaw_threads(thid_t tid, bool exclude=true);
void set_thread_state(thread_info_t &ti, thstate_t state) const;
bool resume_app(thid_t tid);
bool has_pending_events(void);
bool read_asciiz(tid_t tid, ea_t ea, char *buf, size_t bufsize, bool suspend=false);
int _read_memory(int tid, ea_t ea, void *buffer, int size, bool suspend=false);
int _write_memory(int tid, ea_t ea, const void *buffer, int size, bool suspend=false);
void add_dll(ea_t base, asize_t size, const char *modname, const char *soname);
asize_t calc_module_size(const meminfo_vec_t &miv, const memory_info_t *mi) const;
void enum_names(const char *libpath=NULL);
bool add_shlib_bpt(const meminfo_vec_t &miv, bool attaching);
bool gen_library_events(int tid);
bool emulate_retn(int tid);
void cleanup(void);
bool handle_process_start(pid_t pid, attach_mode_t attaching);
drc_t get_memory_info(meminfo_vec_t &areas, bool suspend);
bool set_hwbpts(HANDLE hThread) const;
virtual bool refresh_hwbpts() override;
void handle_dll_movements(const meminfo_vec_t &miv);
bool idaapi thread_get_fs_base(thid_t tid, int reg_idx, ea_t *pea) const;
bool read_mapping(mapfp_entry_t *me);
bool get_soname(const char *fname, qstring *soname) const;
ea_t find_pending_name(const char *name);
bool handle_hwbpt(debug_event_t *event);
bool thread_is_known(const td_thrinfo_t &info) const;
bool listen_thread_events(const td_thrinfo_t &info, const td_thrhandle_t *th_p);
void attach_to_thread(const td_thrinfo_t &info);
void attach_to_thread(int tid, ea_t ea);
bool check_for_new_events(chk_signal_info_t *csi, bool *event_prepared);
void handle_extended_wait(bool *handled, const chk_signal_info_t &csi);
//
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
virtual void idaapi dbg_term(void) override;
virtual drc_t idaapi dbg_detach_process(void) override;
virtual drc_t idaapi dbg_start_process(
const char *path,
const char *args,
const char *startdir,
int flags,
const char *input_path,
uint32 input_file_crc32,
qstring *errbuf) override;
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
virtual drc_t idaapi dbg_attach_process(pid_t process_id, int event_id, int flags, qstring *errbuf) override;
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
virtual void idaapi dbg_stopped_at_debug_event(import_infos_t *infos, bool dlls_added, thread_name_vec_t *thr_names) override;
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
virtual drc_t idaapi dbg_read_registers(
thid_t thread_id,
int clsmask,
regval_t *values,
qstring *errbuf) override;
virtual drc_t idaapi dbg_write_register(
thid_t thread_id,
int reg_idx,
const regval_t *value,
qstring *errbuf) override;
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) override;
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &areas, qstring *errbuf) override;
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
virtual int idaapi handle_ioctl(int fn, const void *buf, size_t size, void **outbuf, ssize_t *outsize) override;
virtual bool idaapi write_registers(
thid_t tid,
int start,
int count,
const regval_t *values) override;
virtual int dbg_freeze_threads_except(thid_t tid) override { return dbg_freeze_threads(tid); }
virtual int dbg_thaw_threads_except(thid_t tid) override { return dbg_thaw_threads(tid); }
virtual bool idaapi dbg_continue_broken_connection(pid_t pid) override;
virtual bool idaapi dbg_prepare_broken_connection(void) override;
// thread_db
void display_thrinfo(thid_t tid);
void display_all_threads();
void cleanup_breakpoints(void);
void cleanup_signals(void);
bool fix_instruction_pointer(void) const;
#ifdef __ARM__
virtual void adjust_swbpt(ea_t *p_ea, int *p_len) override;
#endif
#ifdef LDEB
void log(thid_t tid, const char *format, ...);
#endif
};
#endif

View File

@@ -0,0 +1,15 @@
{
global:
PLUGIN;
ps_pglobal_lookup;
ps_pdread;
ps_pdwrite;
ps_lgetregs;
ps_lsetregs;
ps_lgetfpregs;
ps_lsetfpregs;
ps_getpid;
ps_get_thread_area;
local:
*;
};

View File

@@ -0,0 +1,66 @@
#include <loader.hpp>
//--------------------------------------------------------------------------
// installs or uninstalls debugger specific idc functions
inline bool register_idc_funcs(bool)
{
return true;
}
//--------------------------------------------------------------------------
void idaapi rebase_if_required_to(ea_t new_base)
{
ea_t base = get_imagebase();
if ( base != BADADDR && new_base != BADADDR && base != new_base )
rebase_or_warn(base, new_base);
}
//--------------------------------------------------------------------------
static bool init_plugin(void)
{
#ifndef RPC_CLIENT
if ( !init_subsystem() )
return false;
#endif
bool ok = false;
do
{
if ( !netnode::inited() || is_miniidb() || inf_is_snapshot() )
{
#ifdef __LINUX__
// local debugger is available if we are running under Linux
return true;
#else
// for other systems only the remote debugger is available
if ( debugger.is_remote() )
return true;
break; // failed
#endif
}
if ( inf_get_filetype() != f_ELF )
break;
processor_t &ph = PH;
if ( ph.id != TARGET_PROCESSOR && ph.id != -1 )
break;
ok = true;
} while ( false );
#ifndef RPC_CLIENT
if ( !ok )
term_subsystem();
#endif
return ok;
}
//--------------------------------------------------------------------------
inline void term_plugin(void)
{
#ifndef RPC_CLIENT
term_subsystem();
#endif
}
//--------------------------------------------------------------------------
static const char comment[] = "Userland linux debugger plugin.";

View File

@@ -0,0 +1,34 @@
#define REMOTE_DEBUGGER
#define RPC_CLIENT
static const char wanted_name[] = "Remote Linux debugger";
#define DEBUGGER_NAME "linux"
#define PROCESSOR_NAME "metapc"
#define DEFAULT_PLATFORM_NAME "linux"
#define TARGET_PROCESSOR PLFM_386
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_LINUX_USER
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
| DBG_FLAG_LOWCNDS \
| DBG_FLAG_DEBTHREAD)
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
#define HAVE_APPCALL
#define S_FILETYPE f_ELF
#include <pro.h>
#include <idp.hpp>
#include <idd.hpp>
#include <ua.hpp>
#include <range.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <network.hpp>
#include "dbg_rpc_client.h"
#include "rpc_debmod.h"
rpc_debmod_t g_dbgmod(DEFAULT_PLATFORM_NAME);
#include "common_stub_impl.cpp"
#include "pc_local_impl.cpp"
#include "linux_local_impl.cpp"
#include "common_local_impl.cpp"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
static const char wanted_name[] = "Local Linux debugger";
#define DEBUGGER_NAME "linux"
#define PROCESSOR_NAME "metapc"
#define TARGET_PROCESSOR PLFM_386
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_LINUX_USER
#define DEBUGGER_FLAGS (DBG_FLAG_LOWCNDS \
| DBG_FLAG_DEBTHREAD)
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
#define HAVE_APPCALL
#define S_FILETYPE f_ELF
#include <fpro.h>
#include <idd.hpp>
#include <ua.hpp>
#include <range.hpp>
#include <loader.hpp>
#include "linux_debmod.h"
linux_debmod_t g_dbgmod;
bool ignore_sigint = false;
#include "common_stub_impl.cpp"
#include "pc_local_impl.cpp"
#include "linux_local_impl.cpp"
#include "common_local_impl.cpp"

View File

@@ -0,0 +1,8 @@
#include <pro.h>
#include "linux_debmod.h"
//--------------------------------------------------------------------------
pid_t linux_debmod_t::check_for_signal(int *status, int _pid, int timeout_ms) const
{
return qwait_timed(status, _pid, __WALL | WCONTINUED, timeout_ms);
}

View File

@@ -0,0 +1,138 @@
#include <fpro.h>
#include <prodir.h>
#include <diskio.hpp>
#include "linuxbase_debmod.h"
//--------------------------------------------------------------------------
static inline const char *str_bitness(int bitness)
{
switch ( bitness )
{
case 8:
return "[64]";
case 4:
return "[32]";
default:
return "[x]";
}
}
//--------------------------------------------------------------------------
static void build_process_ext_name(ext_process_info_t *pinfo)
{
pinfo->ext_name = str_bitness(pinfo->addrsize);
char buf[QMAXPATH];
qsnprintf(buf, sizeof(buf), "/proc/%u/cmdline", pinfo->pid);
FILE *cmdfp = qfopen(buf, "r");
if ( cmdfp == nullptr )
return;
int size = qfread(cmdfp, buf, sizeof(buf));
qfclose(cmdfp);
for ( int i=0; i < size; )
{
const char *in = &buf[i];
qstring arg = in;
quote_cmdline_arg(&arg);
pinfo->ext_name.append(" ");
pinfo->ext_name.append(arg);
i += strlen(in) + 1;
}
}
//--------------------------------------------------------------------------
// Returns the file name assciated with pid
bool idaapi linuxbase_debmod_t::get_exec_fname(
int _pid,
char *buf,
size_t bufsize)
{
char path[QMAXPATH];
qsnprintf(path, sizeof(path), "/proc/%u/exe", _pid);
int len = readlink(path, buf, bufsize-1);
if ( len > 0 )
{
buf[len] = '\0';
return true;
}
else
{
// ESXi keeps the real file name inside /proc/PID/exe (which is not a link)
FILE *fp = qfopen(path, "r");
if ( fp != NULL )
{
len = qfread(fp, buf, bufsize);
qfclose(fp);
if ( len > 1 && len < bufsize && buf[0] == '/' ) // sanity check
{
buf[len] = '\0';
return true;
}
}
buf[0] = '\0';
return false;
}
}
//--------------------------------------------------------------------------
// Get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
int idaapi linuxbase_debmod_t::get_process_bitness(int _pid)
{
char fname[QMAXPATH];
qsnprintf(fname, sizeof(fname), "/proc/%u/maps", _pid);
FILE *mapfp = fopenRT(fname);
if ( mapfp == NULL )
return 0;
int bitness = 4;
qstring line;
while ( qgetline(&line, mapfp) >= 0 )
{
if ( line.empty() )
continue;
ea_t ea1;
ea_t ea2;
if ( qsscanf(line.begin(), "%a-%a ", &ea1, &ea2) == 2 )
{
size_t pos = line.find('-');
if ( pos != qstring::npos && pos > 8 )
{
bitness = 8;
break;
}
}
}
qfclose(mapfp);
return bitness;
}
//--------------------------------------------------------------------------
int idaapi linuxbase_debmod_t::get_process_list(procvec_t *list, qstring *)
{
int mypid = getpid();
list->clear();
qffblk64_t fb;
for ( int code = qfindfirst("/proc/*", &fb, FA_DIREC);
code == 0;
code = qfindnext(&fb) )
{
if ( !qisdigit(fb.ff_name[0]) )
continue;
ext_process_info_t pinfo;
pinfo.pid = atoi(fb.ff_name);
if ( pinfo.pid == mypid )
continue;
char buf[MAXSTR];
if ( !get_exec_fname(pinfo.pid, buf, sizeof(buf)) )
continue; // we skip the process because we cannot debug it anyway
pinfo.name = buf;
pinfo.addrsize = get_process_bitness(pinfo.pid);
build_process_ext_name(&pinfo);
list->push_back(pinfo);
}
return list->size();
}

View File

@@ -0,0 +1,30 @@
#ifndef __LINUXBASE_HPP__
#define __LINUXBASE_HPP__
#include "debmod.h"
// Base class for linux modules
#ifdef __ARM__
# define BASE_DEBUGGER_MODULE arm_debmod_t
# include "arm_debmod.h"
# define BPT_CODE_SIZE ARM_BPT_SIZE
#else
# define BASE_DEBUGGER_MODULE pc_debmod_t
# include "pc_debmod.h"
# define BPT_CODE_SIZE X86_BPT_SIZE
#endif
class linuxbase_debmod_t: public BASE_DEBUGGER_MODULE
{
typedef BASE_DEBUGGER_MODULE inherited;
protected:
// return number of processes, -1 - not implemented
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf) override;
// return the file name assciated with pid
virtual bool idaapi get_exec_fname(int pid, char *buf, size_t bufsize) newapi;
// get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
virtual int idaapi get_process_bitness(int pid) newapi;
};
#endif

149
idasdk75/dbg/linux/makefile Normal file
View File

@@ -0,0 +1,149 @@
include ../../allmake.mak
GOALS-$(BUILD_IDA) += modules # target in $(IDA)module.mak
GOALS-$(BUILD_DBGSRV) += server # target in $(IDA)dbg/server.mak
.PHONY: $(GOALS-1)
all: $(GOALS-1)
#----------------------------------------------------------------------
ifdef __LINUX__
SERVER = linux_server$(SUFF64)
endif
ifdef SERVER
SERVERS += $(call server_exe,$(SERVER))
endif
#----------------------------------------------------------------------
USER = $(call module_dll,linux_user)
ifeq ($(and $(BUILD_IDA),$(__LINUX__)),1)
MODULES += $(USER)
endif
#----------------------------------------------------------------------
# we explicitly added our module targets
NO_DEFAULT_TARGETS = 1
# NOTE: all MODULES must be defined before including plugin.mak.
include ../plugin.mak
# NOTE: target-specific rules and dependencies that use variable
# expansion to name the target (such as "$(MODULE): [...]") must
# come after including plugin.mak
#----------------------------------------------------------------------
# select OBJS common to user plugin and debugger server
ifeq ($(or $(__LINUX__),$(__ANDROID__),$(__ANDROID_X86__),$(__ARMLINUX__)),1)
BUILD_LINUX:=1
endif
BASE_OBJS-$(BUILD_LINUX) += $(F)linuxbase_debmod$(O)
BASE_OBJS-$(BUILD_LINUX) += $(F)linux_debmod$(O)
BASE_OBJS-$(BUILD_LINUX) += $(F)linux_wait$(O)
BASE_OBJS += $(BASE_OBJS-1) $(F)symelf$(O)
#----------------------------------------------------------------------
ifdef __LINUX__
SERVER_LDFLAGS += -Wl,--version-script=linux_debmod.script
SERVER_LDFLAGS += $(OUTMAP)$(F)$(@F).map
SERVER_STDLIBS += -lthread_db -lrt -lc -lpthread -ldl
endif
SERVER_OBJS += $(BASE_OBJS)
# suppress warnings for libthread_db.c
$(F)libthread_db$(O): WARNS = $(NOWARNS)
include ../server.mak
#----------------------------------------------------------------------
STUB_OBJS += $(F)linux_stub$(O)
$(STUB): MODULE_OBJS += $(STUB_OBJS)
$(STUB): $(STUB_OBJS)
#----------------------------------------------------------------------
USER_OBJS += $(F)linux_user$(O)
USER_OBJS += $(BASE_OBJS)
$(USER): MODULE_OBJS += $(USER_OBJS)
$(USER): $(USER_OBJS)
$(USER): DEFFILE = linux_debmod.script
$(USER): STDLIBS += -ldl
$(USER): STDLIBS += -lthread_db
ifeq ($(COMPILER_NAME),gcc)
$(USER): LDFLAGS += -Wl,--export-dynamic
endif
#----------------------------------------------------------------------
include $(IDA)objdir.mak
# MAKEDEP dependency list ------------------
$(F)armlinux_stub$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../arm_local_impl.cpp ../arm_regs.cpp ../arm_regs.hpp \
../common_local_impl.cpp ../common_stub_impl.cpp \
../dbg_rpc_client.h ../dbg_rpc_engine.h ../deb_arm.hpp \
../debmod.h ../rpc_debmod.h armlinux_stub.cpp \
linux_local_impl.cpp
$(F)libthread_db$(O): libthread_db.c
$(F)linux_debmod$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)diskio.hpp $(I)err.h $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp $(I)pro.h \
$(I)prodir.h $(I)range.hpp $(I)segment.hpp $(I)ua.hpp \
$(I)xref.hpp ../../plugins/dwarf/look_for_debug_file.cpp \
../arm_debmod.h ../arm_regs.hpp ../dbg_rpc_engine.h \
../dbg_rpc_handler.h ../dbg_rpc_handler_ioctls.h \
../deb_arm.hpp ../deb_pc.hpp ../debmod.h ../pc_debmod.h \
../pc_regs.hpp android.cpp android.hpp linux_debmod.cpp \
linux_debmod.h linux_threads.cpp linuxbase_debmod.h \
symelf.hpp
$(F)linux_stub$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../common_local_impl.cpp ../common_stub_impl.cpp \
../dbg_rpc_client.h ../dbg_rpc_engine.h ../deb_pc.hpp \
../debmod.h ../pc_local_impl.cpp ../pc_regs.hpp \
../rpc_debmod.h linux_local_impl.cpp linux_stub.cpp
$(F)linux_user$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../arm_debmod.h ../common_local_impl.cpp \
../common_stub_impl.cpp ../deb_arm.hpp ../deb_pc.hpp \
../debmod.h ../pc_debmod.h ../pc_local_impl.cpp \
../pc_regs.hpp linux_debmod.h linux_local_impl.cpp \
linux_user.cpp linuxbase_debmod.h
$(F)linux_wait$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)ua.hpp \
$(I)xref.hpp ../arm_debmod.h ../deb_arm.hpp \
../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \
linux_debmod.h linux_wait.cpp linuxbase_debmod.h
$(F)linuxbase_debmod$(O): $(I)bytes.hpp $(I)diskio.hpp $(I)fpro.h \
$(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp $(I)lines.hpp \
$(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)prodir.h $(I)range.hpp \
$(I)ua.hpp $(I)xref.hpp ../arm_debmod.h ../deb_arm.hpp \
../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \
linuxbase_debmod.cpp linuxbase_debmod.h
$(F)symelf$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp \
$(I)offset.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
symelf.hpp

View File

@@ -0,0 +1,239 @@
// read elf symbols
#include <fpro.h>
#include <kernwin.hpp>
#include <diskio.hpp>
#include "../../ldr/elf/elfbase.h"
#include "../../ldr/elf/elf.h"
#include "debmod.h"
#include "symelf.hpp"
#include "../../ldr/elf/common.cpp"
#include "../../ldr/elf/reader.cpp"
inline uint32 low(uint32 x) { return x; }
uval_t imagebase;
//--------------------------------------------------------------------------
//lint -e{1764} could be declared const ref
static int handle_symbol(
reader_t &reader,
int shndx,
int _info,
uint32 st_name,
uval_t st_value,
slice_type_t slice_type,
symbol_visitor_t &sv)
{
if ( shndx == SHN_UNDEF
|| shndx == SHN_LOPROC
|| shndx == SHN_HIPROC
|| shndx == SHN_ABS )
{
return 0;
}
int type = ELF_ST_TYPE(_info);
if ( type != STT_OBJECT && type != STT_FUNC )
return 0;
if ( st_name == 0 )
return 0;
if ( imagebase != uval_t(-1) )
st_value -= imagebase;
qstring name;
reader.get_name(&name, slice_type, st_name);
return sv.visit_symbol(st_value, name.c_str());
}
//--------------------------------------------------------------------------
static int load_symbols(
reader_t &reader,
const elf_shdr_t &section,
slice_type_t slice_type,
symbol_visitor_t &sv)
{
int code = 0;
sym_rel *sym;
buffered_input_t<sym_rel> symbols_input(reader, section);
for ( elf_sym_idx_t i = 0; code == 0 && symbols_input.next(sym); ++i )
{
if ( i == 0 ) // skip _UNDEF
continue;
code = handle_symbol(reader,
sym->original.st_shndx,
sym->original.st_info,
sym->original.st_name,
sym->original.st_value,
slice_type,
sv);
}
return code;
}
//--------------------------------------------------------------------------
static bool map_pht(reader_t &reader)
{
if ( !reader.read_program_headers() )
return false;
imagebase = reader.pheaders.get_image_base();
return true;
}
//----------------------------------------------------------------------------
static bool silent_handler(const reader_t &reader, reader_t::errcode_t code, ...)
{
return reader.is_warning(code); // resume after warnings
}
//--------------------------------------------------------------------------
static int _load_elf_symbols(linput_t *li, symbol_visitor_t &sv)
{
reader_t reader(li);
reader.set_handler(silent_handler);
if ( !reader.read_ident() || !reader.read_header() )
return -1;
const elf_ident_t &ident = reader.get_ident();
uint8 elf_class = ident.elf_class;
if ( elf_class != ELFCLASS32 && elf_class != ELFCLASS64 )
return -1;
uint8 elf_data_ord = ident.bytesex;
if ( elf_data_ord != ELFDATA2LSB && elf_data_ord != ELFDATA2MSB )
return -1;
section_headers_t &sections = reader.sections;
dynamic_linking_tables_t dlt;
int code = 0;
elf_ehdr_t &header = reader.get_header();
if ( header.has_pht() && !map_pht(reader) )
return -1;
reader.read_section_headers();
// Try and acquire dynamic linking tables info.
dlt = reader.sections.get_dynamic_linking_tables_info();
if ( !dlt.is_valid() )
dlt = reader.pheaders.get_dynamic_linking_tables_info();
// Parse dynamic info if available
dynamic_info_t di;
if ( dlt.is_valid() )
{
reader_t::dyninfo_tags_t dyninfo_tags;
dyninfo_tags.reserve(10);
if ( reader.read_dynamic_info_tags(&dyninfo_tags, dlt)
&& reader.parse_dynamic_info(&di, dyninfo_tags)
&& (sv.velf & VISIT_DYNINFO) != 0 )
{
reader.set_di_strtab(reader.dyn_strtab, di.strtab());
typedef reader_t::dyninfo_tags_t::const_iterator const_it;
for ( const_it dyn = dyninfo_tags.begin();
dyn != dyninfo_tags.end();
++dyn )
{
qstring name;
switch ( dyn->d_tag )
{
case DT_SONAME:
case DT_RPATH:
case DT_RUNPATH:
case DT_NEEDED:
reader.get_name(&name, reader.dyn_strtab, uint32(dyn->d_un));
break;
}
if ( sv.visit_dyninfo(dyn->d_tag, name.c_str(), dyn->d_un) != 0 )
break;
};
}
}
if ( (sv.velf & VISIT_INTERP) != 0 )
{
elf_shdr_t *interp_sh = reader.sections.get_wks(WKS_INTERP);
if ( interp_sh != NULL )
{
qstring name;
reader.get_string_at(&name, interp_sh->sh_offset);
code = sv.visit_interp(name.c_str());
if ( code != 0 )
return code;
}
}
if ( (sv.velf & VISIT_SYMBOLS) != 0 )
{
elf_shndx_t symtab = sections.get_index(WKS_SYMTAB);
elf_shndx_t dynsym = sections.get_index(WKS_DYNSYM);
elf_shdr_t fake_section;
if ( symtab != 0 || dynsym != 0 )
{
// Loading symbols
if ( symtab != 0 )
code = load_symbols(reader, *sections.getn(symtab), SLT_SYMTAB, sv);
if ( code == 0 && dynsym != 0 )
code = load_symbols(reader, *sections.getn(dynsym), SLT_DYNSYM, sv);
}
else if ( di.fill_section_header(&fake_section, DIT_SYMTAB) )
{
code = load_symbols(reader, fake_section, SLT_DYNSYM, sv);
}
}
notes_t notes(&reader);
if ( (sv.velf & VISIT_BUILDID) != 0 && reader.read_notes(&notes) )
{
qstring id;
if ( notes.get_build_id(&id) )
{
code = sv.visit_buildid(id.c_str());
if ( code != 0 )
return code;
}
}
if ( (sv.velf & VISIT_DBGLINK ) != 0 )
{
uint32 crc;
qstring debuglink;
if ( sections.is_initialized()
&& sections.read_gnu_debuglink(&debuglink, &crc) )
{
code = sv.visit_debuglink(debuglink.c_str(), crc);
if ( code != 0 )
return code;
}
}
return code;
}
//--------------------------------------------------------------------------
static int load_linput_elf_symbols(linput_t *li, symbol_visitor_t &sv)
{
if ( li == NULL )
return -1;
int code;
// there is thread unsafe code in elf handling, so use locks
lock_begin();
{
code = _load_elf_symbols(li, sv);
}
lock_end();
close_linput(li);
return code;
}
//--------------------------------------------------------------------------
int load_elf_symbols(const char *fname, symbol_visitor_t &sv, bool remote)
{
return load_linput_elf_symbols(open_linput(fname, remote), sv);
}

View File

@@ -0,0 +1,30 @@
// read symbols from an elf file
#ifndef __SYMELF__
#define __SYMELF__
struct symbol_visitor_t
{
symbol_visitor_t(int visit_flags) : velf(visit_flags) {}
int velf;
#define VISIT_SYMBOLS 0x0001
#define VISIT_INTERP 0x0002
#define VISIT_DYNINFO 0x0004
#define VISIT_SEGMENTS 0x0008
#define VISIT_BUILDID 0x0010
#define VISIT_DBGLINK 0x0020
// any callback returns nonzero - stop enumeration
virtual int visit_symbol(ea_t /*ea*/, const char * /*name*/) { return 0; }
virtual int visit_interp(const char * /*name*/) { return 0; }
virtual int visit_segment(ea_t /*start*/, size_t /*size*/, const char * /*name*/) { return 0; }
virtual int visit_dyninfo(uint64 /*tag*/, const char * /*name*/, uint64 /*value*/) { return 0; }
virtual int visit_buildid(const char * /*Build ID*/) { return 0; }
virtual int visit_debuglink(const char * /*debug*/, uint32 /*crc*/) { return 0; }
};
// returns -1 on errors
// otherwise returns the non-zero code returned by the visitor or 0
int load_elf_symbols(const char *fname, symbol_visitor_t &sv, bool remote=false);
#endif

View File

@@ -0,0 +1,23 @@
// This option is ideal when working with the Remote Mac OSX Debugger.
// It allows IDA to parse symbol data for dyld_shared_cache libs locally, rather than
// transferring symbol names over the wire, which can save a significant amount of time.
//
// Here's an example of how to use it:
//
// First download the ios_deploy utility at: https://www.hex-rays.com/products/ida/support/ida/ios_deploy.zip.
// Then run the following commands on the remote OSX machine:
//
// $ mkdir ~/Symbols
// $ ios_deploy symbols -c /var/db/dyld/dyld_shared_cache_x86_64h -d ~/Symbols
// $ ios_deploy symbols -c /var/db/dyld/dyld_shared_cache_i386 -d ~/Symbols
//
// Then, on the client machine running IDA:
//
// $ scp -r user@mac:Symbols ~/
// set SYMBOL_PATH = "~/Symbols" in dbg_macosx.cfg
// start IDA and run the debugger, symbol loading should now be much faster
//
// Any errors will be printed to the console.
SYMBOL_PATH = "";

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,546 @@
#ifndef __MAC_DEBUGGER_MODULE__
#define __MAC_DEBUGGER_MODULE__
/*
* This is the mach (MAC OS X) debugger module
*
* Functions unique for Mach (MAC OS X)
*
*/
#include <map>
#include <pro.h>
#include <fpro.h>
#include <err.h>
#include <ida.hpp>
#include <idp.hpp>
#include <idd.hpp>
#include <name.hpp>
#include <bytes.hpp>
#include <loader.hpp>
#include <diskio.hpp>
#include <ua.hpp>
#define MD msg("at line %d\n", __LINE__);
#define processor_t mach_processor_t
#include <grp.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <mach-o/reloc.h>
#include <mach-o/nlist.h>
#include <mach-o/fat.h>
#include <mach/mach.h>
#include <mach/shared_region.h>
#include <Security/Security.h>
#include <Security/SecCode.h> // needed for SDK versions <= 10.7
#undef processor_t
#include "macbase_debmod.h"
typedef int HANDLE;
class mac_debmod_t;
#define INVALID_HANDLE_VALUE (-1)
//--------------------------------------------------------------------------
//
// DEBUGGER INTERNAL DATA
//
//--------------------------------------------------------------------------
enum run_state_t
{
rs_running,
rs_pausing,
rs_suspended, // used by iphone
rs_exiting,
rs_exited
};
// image information
struct image_info_t
{
ea_t base;
asize_t size;
qstring name;
bytevec_t uuid;
image_info_t() { clear(); }
image_info_t(ea_t _base, uint32 _size, const qstring &_name, const bytevec_t &_uuid)
: base(_base), size(_size), name(_name), uuid(_uuid) {}
void clear()
{
base = BADADDR;
size = 0;
name.clear();
uuid.clear();
}
};
typedef std::map<ea_t, image_info_t> images_t; // key: image base address
union my_mach_msg_t
{
mach_msg_header_t hdr;
char data[1024];
void display(const char *header);
};
//--------------------------------------------------------------------------
enum block_type_t
{
bl_none, // process is running
bl_signal, // blocked due to a signal (must say PTRACE_CONT)
bl_exception, // blocked due to an exception (must say task_resume())
};
//--------------------------------------------------------------------------
// thread information
//-V:ida_thread_info_t:730 Not all members of a class are initialized inside the constructor. Consider inspecting: excmsg.
struct ida_thread_info_t
{
ida_thread_info_t(thid_t t, mach_port_t p)
: tid(t), port(p), child_signum(0), asked_step(false), single_step(false),
pending_sigstop(false), block(bl_none), run_handled(false) {}
int tid;
mach_port_t port;
int child_signum;
bool asked_step;
bool single_step;
bool pending_sigstop;
block_type_t block;
my_mach_msg_t excmsg;
bool run_handled;
bool blocked(void) const { return block != bl_none; }
};
typedef std::map<int, ida_thread_info_t> threads_t; // (tid -> info)
//--------------------------------------------------------------------------
struct mach_exception_port_info_t
{
exception_mask_t masks[EXC_TYPES_COUNT];
mach_port_t ports[EXC_TYPES_COUNT];
exception_behavior_t behaviors[EXC_TYPES_COUNT];
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
mach_msg_type_number_t count;
};
typedef qvector<struct nlist_64> nlists_t;
//--------------------------------------------------------------------------
struct mach_exception_info_t
{
task_t task_port;
thread_t thread_port;
exception_type_t exception_type;
exception_data_t exception_data;
mach_msg_type_number_t data_count;
};
//--------------------------------------------------------------------------
typedef janitor_t<AuthorizationRef> auth_ref_janitor_t;
template <> inline auth_ref_janitor_t::~janitor_t()
{
if ( resource != NULL )
AuthorizationFree(resource, kAuthorizationFlagDefaults);
}
//--------------------------------------------------------------------------
typedef janitor_t<AuthorizationRights *> auth_rights_janitor_t;
template <> inline auth_rights_janitor_t::~janitor_t()
{
if ( resource != NULL )
AuthorizationFreeItemSet(resource);
}
//--------------------------------------------------------------------------
typedef janitor_t<SecCodeRef> sec_code_janitor_t;
template <> inline sec_code_janitor_t::~janitor_t()
{
if ( resource != NULL )
CFRelease(resource);
}
struct vm_region_visitor_t
{
virtual int visit_region(memory_info_t &mi) = 0;
};
//--------------------------------------------------------------------------
struct machine_thread_state_t
{
ea_t __eax;
ea_t __ebx;
ea_t __ecx;
ea_t __edx;
ea_t __edi;
ea_t __esi;
ea_t __ebp;
ea_t __esp;
ea_t __eip;
ea_t __r8;
ea_t __r9;
ea_t __r10;
ea_t __r11;
ea_t __r12;
ea_t __r13;
ea_t __r14;
ea_t __r15;
ea_t __eflags;
ea_t __ss;
ea_t __cs;
ea_t __ds;
ea_t __es;
ea_t __fs;
ea_t __gs;
};
//--------------------------------------------------------------------------
struct machine_float_state_t
{
uint16 __fpu_fcw;
uint16 __fpu_fsw;
uint8 __fpu_ftw;
uint16 __fpu_fop;
uint32 __fpu_ip;
uint16 __fpu_cs;
uint32 __fpu_dp;
uint16 __fpu_ds;
uint32 __fpu_mxcsr;
uint32 __fpu_mxcsrmask;
_STRUCT_MMST_REG __fpu_stmm0;
_STRUCT_MMST_REG __fpu_stmm1;
_STRUCT_MMST_REG __fpu_stmm2;
_STRUCT_MMST_REG __fpu_stmm3;
_STRUCT_MMST_REG __fpu_stmm4;
_STRUCT_MMST_REG __fpu_stmm5;
_STRUCT_MMST_REG __fpu_stmm6;
_STRUCT_MMST_REG __fpu_stmm7;
_STRUCT_XMM_REG __fpu_xmm0;
_STRUCT_XMM_REG __fpu_xmm1;
_STRUCT_XMM_REG __fpu_xmm2;
_STRUCT_XMM_REG __fpu_xmm3;
_STRUCT_XMM_REG __fpu_xmm4;
_STRUCT_XMM_REG __fpu_xmm5;
_STRUCT_XMM_REG __fpu_xmm6;
_STRUCT_XMM_REG __fpu_xmm7;
_STRUCT_XMM_REG __fpu_xmm8;
_STRUCT_XMM_REG __fpu_xmm9;
_STRUCT_XMM_REG __fpu_xmm10;
_STRUCT_XMM_REG __fpu_xmm11;
_STRUCT_XMM_REG __fpu_xmm12;
_STRUCT_XMM_REG __fpu_xmm13;
_STRUCT_XMM_REG __fpu_xmm14;
_STRUCT_XMM_REG __fpu_xmm15;
_STRUCT_XMM_REG __fpu_ymmh0;
_STRUCT_XMM_REG __fpu_ymmh1;
_STRUCT_XMM_REG __fpu_ymmh2;
_STRUCT_XMM_REG __fpu_ymmh3;
_STRUCT_XMM_REG __fpu_ymmh4;
_STRUCT_XMM_REG __fpu_ymmh5;
_STRUCT_XMM_REG __fpu_ymmh6;
_STRUCT_XMM_REG __fpu_ymmh7;
_STRUCT_XMM_REG __fpu_ymmh8;
_STRUCT_XMM_REG __fpu_ymmh9;
_STRUCT_XMM_REG __fpu_ymmh10;
_STRUCT_XMM_REG __fpu_ymmh11;
_STRUCT_XMM_REG __fpu_ymmh12;
_STRUCT_XMM_REG __fpu_ymmh13;
_STRUCT_XMM_REG __fpu_ymmh14;
_STRUCT_XMM_REG __fpu_ymmh15;
};
//--------------------------------------------------------------------------
struct machine_debug_state_t
{
ea_t __dr0;
ea_t __dr1;
ea_t __dr2;
ea_t __dr3;
ea_t __dr4;
ea_t __dr5;
ea_t __dr6;
ea_t __dr7;
};
//--------------------------------------------------------------------------
class mac_debmod_t: public macbase_debmod_t
{
typedef macbase_debmod_t inherited;
public:
procinfo_vec_t processes;
// debugged process information
mach_port_t task; // debugged application's task port
cpu_type_t cputype; // process' CPU type (e.g. CPU_TYPE_I386 or CPU_TYPE_X86_64)
bool in_ptrace; // We use ptrace to start the debugging session
// but since it is badly broken, we detach and
// revert to low-level mach api immediately after that
run_state_t run_state;
dyld_utils_t dyld;
image_info_t exeimg; // image info for the exe module
images_t dlls; // list of loaded dynamic libraries
easet_t dlls_to_import; // list of dlls to import information from
inline bool exited(void)
{
return run_state == rs_exited;
}
threads_t threads;
struct stored_signal_t
{
pid_t pid;
int status;
};
typedef qvector<stored_signal_t> stored_signals_t;
static stored_signals_t pending_signals; // signals retrieved by other threads
bool attaching; // Handling events linked to PTRACE_ATTACH, don't run the program yet
bool is64; // is target 64-bit?
mach_port_t exc_port;
mach_exception_port_info_t saved_exceptions;
regctx_t *reg_ctx;
mac_debmod_t();
~mac_debmod_t();
void init_reg_ctx(void);
void term_reg_ctx(void);
void handle_dyld_bpt(const debug_event_t *event);
bool retrieve_pending_signal(int *status);
kern_return_t read_mem(ea_t ea, void *buffer, int size, int *read_size);
void unblock_all_threads();
void resume_all_threads();
bool suspend_all_threads();
bool my_resume_thread(ida_thread_info_t &ti);
pid_t qwait(int *status, bool hang);
void get_debug_events(int timeout_ms);
kern_return_t
catch_exception_raise(mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code_vector,
mach_msg_type_number_t code_count);
ea_t get_ip(thid_t tid);
uval_t get_dr(thid_t tid, int idx);
bool set_dr(thid_t tid, int idx, uval_t value);
bool idaapi thread_get_fs_base(thid_t tid, int reg_idx, ea_t *pea);
bool parse_macho_image(macho_visitor_t &mv, const image_info_t &ii);
void clean_stack_regions(meminfo_vec_t &miv) const;
drc_t get_memory_info(meminfo_vec_t &miv, bool suspend);
void init_dyld(void);
void init_exeimg(pid_t _pid, thid_t tid);
void update_dyld(void);
bool exist_dll(const images_t &images, ea_t base);
virtual bool refresh_hwbpts() override;
virtual bool set_hwbpts(int hThread) newapi;
bool handle_process_start(pid_t _pid);
void term_exception_ports(void);
void init_exception_ports(void);
thid_t init_main_thread(bool reattaching);
bool update_threads(void);
bool thread_exit_event_planned(thid_t tid);
void cleanup(void);
bool xfer_memory(ea_t ea, void *buffer, int size, bool write);
void add_dll(const image_info_t &ii);
int _write_memory(ea_t ea, const void *buffer, int size, bool suspend=false);
int _read_memory(ea_t ea, void *buffer, int size, bool suspend=false);
bool xfer_page(ea_t ea, void *buffer, int size, bool write);
kern_return_t write_mem(ea_t ea, void *buffer, int size);
int exception_to_signal(const mach_exception_info_t *exinf);
bool check_for_exception(int timeout, mach_exception_info_t *exinf);
bool handle_signal(
int code,
debug_event_t *event,
block_type_t block,
const my_mach_msg_t *excmsg);
bool check_for_exception(
int timeout,
mach_exception_info_t *exinf,
my_mach_msg_t *excmsg);
bool is_task_valid(task_t task);
int32 qptrace(int request, pid_t pid, caddr_t addr, int data);
ida_thread_info_t *get_thread(thid_t tid);
int handle_bpts(debug_event_t *event, bool asked_step);
//--------------------------------------------------------------------------
#define DEFINE_GET_STATE_FUNC(name, type, flavor, flavor_count) \
bool name(thid_t tid, type *state) \
{ \
ida_thread_info_t *ti = get_thread(tid); \
if ( ti == NULL ) \
return false; \
mach_port_t port = ti->port; \
mach_msg_type_number_t stateCount = flavor_count; \
kern_return_t err; \
err = thread_get_state(port, \
flavor, \
(thread_state_t)state, \
&stateCount); \
QASSERT(30105, stateCount == flavor_count); \
if ( err != KERN_SUCCESS ) \
{ \
debdeb("tid=%d port=%d: " #name ": %s\n", tid, port, mach_error_string(err)); \
return false; \
} \
return true; \
}
#define DEFINE_SET_STATE_FUNC(name, type, flavor, flavor_count) \
bool name(thid_t tid, const type *state) \
{ \
ida_thread_info_t *ti = get_thread(tid); \
if ( ti == NULL ) \
return false; \
mach_port_t port = ti->port; \
mach_msg_type_number_t stateCount = flavor_count; \
kern_return_t err; \
err = thread_set_state(port, \
flavor, \
(thread_state_t)state, \
stateCount); \
QASSERT(30106, stateCount == flavor_count); \
return err == KERN_SUCCESS; \
}
DEFINE_GET_STATE_FUNC(get_thread_state64, x86_thread_state64_t, x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT)
DEFINE_SET_STATE_FUNC(set_thread_state64, x86_thread_state64_t, x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT)
DEFINE_GET_STATE_FUNC(get_thread_state32, x86_thread_state32_t, x86_THREAD_STATE32, x86_THREAD_STATE32_COUNT)
DEFINE_SET_STATE_FUNC(set_thread_state32, x86_thread_state32_t, x86_THREAD_STATE32, x86_THREAD_STATE32_COUNT)
DEFINE_GET_STATE_FUNC(get_float_state64, x86_avx_state64_t, x86_AVX_STATE64, x86_AVX_STATE64_COUNT)
DEFINE_SET_STATE_FUNC(set_float_state64, x86_avx_state64_t, x86_AVX_STATE64, x86_AVX_STATE64_COUNT)
DEFINE_GET_STATE_FUNC(get_float_state32, x86_avx_state32_t, x86_AVX_STATE32, x86_AVX_STATE32_COUNT)
DEFINE_SET_STATE_FUNC(set_float_state32, x86_avx_state32_t, x86_AVX_STATE32, x86_AVX_STATE32_COUNT)
DEFINE_GET_STATE_FUNC(get_debug_state64, x86_debug_state64_t, x86_DEBUG_STATE64, x86_DEBUG_STATE64_COUNT)
DEFINE_SET_STATE_FUNC(set_debug_state64, x86_debug_state64_t, x86_DEBUG_STATE64, x86_DEBUG_STATE64_COUNT)
DEFINE_GET_STATE_FUNC(get_debug_state32, x86_debug_state32_t, x86_DEBUG_STATE32, x86_DEBUG_STATE32_COUNT)
DEFINE_SET_STATE_FUNC(set_debug_state32, x86_debug_state32_t, x86_DEBUG_STATE32, x86_DEBUG_STATE32_COUNT)
bool get_thread_state(thid_t tid, machine_thread_state_t *state);
bool set_thread_state(thid_t tid, const machine_thread_state_t *state);
bool get_float_state(thid_t tid, machine_float_state_t *state);
bool set_float_state(thid_t tid, const machine_float_state_t *state);
bool get_debug_state(thid_t tid, machine_debug_state_t *state);
bool set_debug_state(thid_t tid, const machine_debug_state_t *state);
bool qthread_setsinglestep(ida_thread_info_t &ti);
bool patch_reg_context(
machine_thread_state_t *cpu,
machine_float_state_t *fpu,
int reg_idx,
const regval_t *value) const;
//--------------------------------------------------------------------------
inline thid_t maintid(void)
{
return threads.begin()->first;
}
void create_process_start_event(pid_t pid, thid_t tid);
void create_process_attach_event(pid_t pid);
//
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
virtual void idaapi dbg_term(void) override;
virtual drc_t idaapi dbg_detach_process(void) override;
virtual drc_t idaapi dbg_start_process(
const char *path,
const char *args,
const char *startdir,
int flags,
const char *input_path,
uint32 input_file_crc32,
qstring *errbuf) override;
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
virtual drc_t idaapi dbg_attach_process(
pid_t process_id,
int event_id,
int flags,
qstring *errbuf) override;
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
virtual void idaapi dbg_stopped_at_debug_event(
import_infos_t *infos,
bool dlls_added,
thread_name_vec_t *thr_names) override;
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
virtual drc_t idaapi dbg_read_registers(
thid_t thread_id,
int clsmask,
regval_t *values,
qstring *errbuf) override;
virtual drc_t idaapi dbg_write_register(
thid_t thread_id,
int reg_idx,
const regval_t *value,
qstring *errbuf) override;
virtual drc_t idaapi dbg_thread_get_sreg_base(
ea_t *ea,
thid_t thread_id,
int sreg_value,
qstring *errbuf) override;
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &miv, qstring *errbuf) override;
virtual int idaapi dbg_get_scattered_image(scattered_image_t &sci, ea_t base) override;
virtual bool idaapi dbg_get_image_uuid(bytevec_t *uuid, ea_t base) override;
virtual ea_t idaapi dbg_get_segm_start(ea_t base, const qstring &segname) override;
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
virtual bool idaapi write_registers(
thid_t tid,
int start,
int count,
const regval_t *values) override;
virtual int dbg_freeze_threads_except(thid_t tid) override;
virtual int dbg_thaw_threads_except(thid_t tid) override;
virtual bool idaapi dbg_continue_broken_connection(pid_t pid) override;
virtual bool idaapi dbg_prepare_broken_connection(void) override;
void get_image_meminfo(meminfo_vec_t &out, const image_info_t &ii);
int get_task_suspend_count(void);
int visit_vm_regions(vm_region_visitor_t &rv);
static bool acquire_taskport_right();
static bool verify_code_signature();
static bool verify_user_privilege();
bool import_symbols(const image_info_t &ii);
virtual bool import_dll(const import_request_t &req) override;
bool get_image_info(image_info_t *ii, ea_t base) const;
};
#endif

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleGetInfoString</key>
<string>OS X Remote Debug Server (32-bit) for IDA, Copyright (c) 2015 Hex-Rays SA</string>
<key>CFBundleExecutable</key>
<string>mac_server</string>
<key>CFBundleIdentifier</key>
<string>com.hexrays.mac_server</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>mac_server</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>SecTaskAccess</key>
<array>
<string>allowed</string>
<string>debug</string>
<string>safe</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleGetInfoString</key>
<string>OS X Remote Debug Server (64-bit) for IDA, Copyright (c) 2015 Hex-Rays SA</string>
<key>CFBundleExecutable</key>
<string>mac_server64</string>
<key>CFBundleIdentifier</key>
<string>com.hexrays.mac_serverx64</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>mac_serverx64</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>SecTaskAccess</key>
<array>
<string>allowed</string>
<string>debug</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,203 @@
#include <loader.hpp>
#include "macho_rebase.cpp"
//--------------------------------------------------------------------------
// installs or uninstalls debugger specific idc functions
inline bool register_idc_funcs(bool)
{
return true;
}
//--------------------------------------------------------------------------
void idaapi rebase_if_required_to(ea_t new_base)
{
// not a shared cache lib: it's safe to just use the imagebase
ea_t base = get_imagebase();
if ( base == 0 )
{
// old databases don't have it set; use info from netnode
netnode n(MACHO_NODE);
if ( exist(n) )
base = n.altval(MACHO_ALT_IMAGEBASE);
}
if ( base != BADADDR
&& new_base != BADADDR
&& base != new_base
&& !rebase_scattered_segments(new_base) )
{
rebase_or_warn(base, new_base);
}
}
//--------------------------------------------------------------------------
enum macopt_idx_t
{
MAC_OPT_SYMBOL_PATH // path to symbols extracted from dyld shared cache
};
//--------------------------------------------------------------------------
struct mac_cfgopt_t
{
const char *name;
char type;
char index;
void *var;
size_t size;
};
//lint -esym(843, g_must_save_cfg) could be declared as const
static bool g_must_save_cfg = false;
//--------------------------------------------------------------------------
static const mac_cfgopt_t g_cfgopts[] =
{
{ "SYMBOL_PATH", IDPOPT_STR, MAC_OPT_SYMBOL_PATH, &g_dbgmod.dyld.symbol_path, 0 },
};
CASSERT(IS_QSTRING(g_dbgmod.dyld.symbol_path));
//--------------------------------------------------------------------------
static const mac_cfgopt_t *find_option(const char *name)
{
for ( int i=0; i < qnumber(g_cfgopts); i++ )
if ( strcmp(g_cfgopts[i].name, name) == 0 )
return &g_cfgopts[i];
return NULL;
}
//--------------------------------------------------------------------------
static void load_mac_options()
{
if ( !netnode::inited() )
return;
netnode node(MAC_NODE);
if ( !exist(node) )
return;
for ( int i = 0; i < qnumber(g_cfgopts); i++ )
{
const mac_cfgopt_t &opt = g_cfgopts[i];
if ( opt.type == IDPOPT_STR )
node.supstr((qstring *)opt.var, opt.index);
else
node.supval(opt.index, opt.var, opt.size);
}
}
//--------------------------------------------------------------------------
static void save_mac_options()
{
if ( !g_must_save_cfg || !netnode::inited() )
return;
netnode node;
node.create(MAC_NODE);
if ( node != BADNODE )
{
for ( int i = 0; i < qnumber(g_cfgopts); i++ )
{
const mac_cfgopt_t &opt = g_cfgopts[i];
if ( opt.type == IDPOPT_STR )
node.supset(opt.index, ((qstring *)opt.var)->c_str(), 0);
else
node.supset(opt.index, opt.var, opt.size);
}
}
g_must_save_cfg = false;
}
//--------------------------------------------------------------------------
const char *idaapi set_mac_options(const char *keyword, int pri, int value_type, const void *value)
{
if ( keyword == NULL )
{
static const char form[] =
"Mac OSX Debugger Options\n%/"
"<#Path to symbol files extracted from dyld_shared_cache#~S~ymbol path:q:1023:60::>\n";
qstring path = g_dbgmod.dyld.symbol_path;
if ( !ask_form(form, NULL, &path) )
return IDPOPT_OK;
g_dbgmod.dyld.symbol_path = path;
g_must_save_cfg = true;
}
else
{
if ( *keyword == '\0' )
{
load_mac_options();
return IDPOPT_OK;
}
const mac_cfgopt_t *opt = find_option(keyword);
if ( opt == NULL )
return IDPOPT_BADKEY;
if ( opt->type != value_type )
return IDPOPT_BADTYPE;
if ( opt->type == IDPOPT_STR )
{
qstring *pvar = (qstring *)opt->var;
*pvar = (char *)value;
}
if ( pri == IDPOPT_PRI_HIGH )
g_must_save_cfg = true;
}
return IDPOPT_OK;
}
//--------------------------------------------------------------------------
static ssize_t idaapi ui_callback(void *, int notification_code, va_list)
{
if ( notification_code == ui_saving )
save_mac_options();
return 0;
}
//--------------------------------------------------------------------------
static bool init_plugin(void)
{
#ifndef RPC_CLIENT
if ( !init_subsystem() )
return false;
#endif
if ( !netnode::inited() || is_miniidb() || inf_is_snapshot() )
{
#ifdef __MAC__
// local debugger is available if we are running under MAC OS X
return true;
#else
// for other systems only the remote debugger is available
return debugger.is_remote();
#endif
}
if ( inf_get_filetype() != S_FILETYPE ) // only Mach-O files
return false;
processor_t &ph = PH;
if ( ph.id != TARGET_PROCESSOR && ph.id != -1 )
return false;
hook_to_notification_point(HT_UI, ui_callback);
return true;
}
//--------------------------------------------------------------------------
inline void term_plugin(void)
{
#ifndef RPC_CLIENT
term_subsystem();
#endif
unhook_from_notification_point(HT_UI, ui_callback);
save_mac_options();
}
//--------------------------------------------------------------------------
static const char comment[] = "Userland Mac OS X debugger plugin.";

View File

@@ -0,0 +1,72 @@
/*
This is the MAC OS X x86 user land debugger entry point file
*/
#ifndef __GNUC__
//lint -esym(750, __LITTLE_ENDIAN__) not referenced
#define __LITTLE_ENDIAN__
#endif
//#define __inline__ inline
#define REMOTE_DEBUGGER
#define RPC_CLIENT
static const char wanted_name[] = "Remote Mac OS X debugger";
#define DEBUGGER_NAME "macosx"
#define PROCESSOR_NAME "metapc"
#define DEFAULT_PLATFORM_NAME "macosx"
#define TARGET_PROCESSOR PLFM_386
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_MACOSX_USER
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
| DBG_FLAG_LOWCNDS \
| DBG_FLAG_DEBTHREAD)
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
#define HAVE_APPCALL
#define S_FILETYPE f_MACHO
#define SET_DBG_OPTIONS set_mac_options
#define MAC_NODE "$ remote mac options"
#include <pro.h>
#include <idp.hpp>
#include <idd.hpp>
#include <ua.hpp>
#include <range.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <name.hpp>
#include <network.hpp>
#include "dbg_rpc_client.h"
#include "rpc_debmod.h"
#include "symmacho.hpp"
class rstub_debmod_t : public rpc_debmod_t
{
typedef rpc_debmod_t inherited;
public:
dyld_utils_t dyld;
rstub_debmod_t() : inherited(DEFAULT_PLATFORM_NAME), dyld(this, TARGET_PROCESSOR) {}
// handle an RPC_IMPORT_DLL request from the server. see SYMBOL_PATH in dbg_macosx.cfg.
virtual bool import_dll(const import_request_t &req) override
{
dyld.update_bitness();
struct ida_local dll_importer_t : public macho_visitor_t
{
dll_importer_t() : macho_visitor_t(MV_SYMBOLS) {}
void visit_symbol(ea_t ea, const char *name) override
{
set_debug_name(ea, name);
}
};
dll_importer_t di;
return dyld.parse_local_symbol_file(req.base, req.path.c_str(), req.uuid, di);
}
};
rstub_debmod_t g_dbgmod;
#include "common_stub_impl.cpp"
#include "pc_local_impl.cpp"
#include "mac_local_impl.cpp"
#include "common_local_impl.cpp"

View File

@@ -0,0 +1,31 @@
/*
This is the MAC user land local debugger entry point file
It declares a MAC debugger module and uses the common plugin functions to build the debugger
*/
static const char wanted_name[] = "Local Mac OS X debugger";
#define DEBUGGER_NAME "macosx"
#define PROCESSOR_NAME "metapc"
#define TARGET_PROCESSOR PLFM_386
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_MACOSX_USER
#define DEBUGGER_FLAGS (DBG_FLAG_LOWCNDS \
| DBG_FLAG_DEBTHREAD)
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
#define HAVE_APPCALL
#define S_FILETYPE f_MACHO
#define SET_DBG_OPTIONS set_mac_options
#define MAC_NODE "$ local mac options"
#include <pro.h>
#include <idd.hpp>
#include <ua.hpp>
#include <range.hpp>
#include <loader.hpp>
#include "mac_debmod.h"
mac_debmod_t g_dbgmod;
#include "common_stub_impl.cpp"
#include "pc_local_impl.cpp"
#include "mac_local_impl.cpp"
#include "common_local_impl.cpp"

View File

@@ -0,0 +1,164 @@
#undef processor_t
#define processor_t mach_processor_t
#include <sys/sysctl.h>
#include <mach/mach.h>
#undef processor_t
#include <fpro.h>
#include <prodir.h>
#include <diskio.hpp>
#include "macbase_debmod.h"
//--------------------------------------------------------------------------
inline const char *str_bitness(int bitness)
{
switch ( bitness )
{
case 8:
return "[64]";
case 4:
return "[32]";
default:
return "[?]";
}
}
//--------------------------------------------------------------------------
cpu_type_t macbase_debmod_t::get_process_cpu(pid_t _pid) const
{
int mib[CTL_MAXNAME];
size_t mibLen = CTL_MAXNAME;
int err = sysctlnametomib("sysctl.proc_cputype", mib, &mibLen);
if ( err == 0 )
{
QASSERT(895, mibLen < CTL_MAXNAME);
mib[mibLen] = _pid;
mibLen += 1;
cpu_type_t cpu_type;
size_t cpuTypeSize = sizeof(cpu_type);
err = sysctl(mib, mibLen, &cpu_type, &cpuTypeSize, 0, 0);
if ( err == 0 )
return cpu_type;
}
msg("error from sysctl: %s\n", strerror(errno));
return 0;
}
//--------------------------------------------------------------------------
static void build_process_ext_name(ext_process_info_t *pinfo)
{
pinfo->ext_name = str_bitness(pinfo->addrsize);
pinfo->ext_name.append(' ');
pinfo->ext_name.append(pinfo->name);
}
//--------------------------------------------------------------------------
// Returns the file name assciated with pid
bool idaapi macbase_debmod_t::get_exec_fname(
int _pid,
char *buf,
size_t bufsize)
{
int mib[3];
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
int argmax = 0;
size_t size = sizeof(argmax);
sysctl(mib, 2, &argmax, &size, NULL, 0);
if ( argmax <= 0 )
argmax = QMAXPATH;
char *args = (char *)qalloc(argmax);
if ( args == NULL )
nomem("get_exec_fname");
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = _pid;
// obtain the arguments for the target process. this will
// only work for processes that belong to the current uid,
// so if you want it to work universally, you need to run
// as root.
size = argmax;
buf[0] = '\0';
if ( sysctl(mib, 3, args, &size, NULL, 0) != -1 )
{
char *ptr = args + sizeof(int);
// show_hex(ptr, size, "procargs2\n");
qstrncpy(buf, ptr, bufsize);
}
qfree(args);
return true;
}
//--------------------------------------------------------------------------
// Get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
int idaapi macbase_debmod_t::get_process_bitness(int _pid)
{
return get_cpu_bitness(get_process_cpu(_pid));
}
//--------------------------------------------------------------------------
int idaapi macbase_debmod_t::get_process_list(procvec_t *list, qstring *)
{
list->clear();
int mypid = getpid();
int sysControl[4];
sysControl[0] = CTL_KERN;
sysControl[1] = KERN_PROC;
sysControl[2] = KERN_PROC_ALL;
qvector<struct kinfo_proc> info;
size_t length;
int count = 0;
int rc = -1;
for ( int tries=0; rc != 0 && tries < 5; ++tries )
{
// the first call of sysctl() is used to determine the size of the buffer
// will be passed to the second call
length = 0;
sysctl(sysControl, 3, NULL, &length, NULL, 0);
// If the number of processes is greater than the size of the buffer
// sysctl() supplies as much data as fits in the buffer and returns ENOMEM.
// We reserve 100 extra elements for processes started after 1st sysctl
// In case even this number is not sufficient we turn to the next attempt
count = (length / sizeof (info[0])) + 100;
if ( count <= 0 ) //-V547 is always false.
return 0;
if ( info.size() < count )
info.resize(count);
length = sizeof(info[0]) * info.size();
rc = sysctl(sysControl, 3, info.begin(), &length, NULL, 0);
if ( rc != 0 && errno != ENOMEM )
return 0;
}
count = (length / sizeof (info[0])); // exact number of processes
for ( int i=0; i < count; i++ )
{
extern_proc &ep = info[i].kp_proc;
pid_t _pid = ep.p_pid;
if ( _pid == mypid )
continue;
mach_port_t port;
kern_return_t result = task_for_pid(mach_task_self(), _pid, &port);
if ( result == KERN_SUCCESS )
{
ext_process_info_t &pi = list->push_back();
pi.name = ep.p_comm;
pi.pid = _pid;
pi.addrsize = get_process_bitness(_pid);
build_process_ext_name(&pi);
}
else
{
debdeb("%d: %s is unavailable for debugging\n", _pid, info[i].kp_proc.p_comm);
}
}
return list->size();
}

View File

@@ -0,0 +1,41 @@
#ifndef __MACBASE_HPP__
#define __MACBASE_HPP__
#include "debmod.h"
#include "pc_debmod.h"
#define BASE_DEBUGGER_MODULE pc_debmod_t
#ifndef __LINUX__ // linux gcc cannot compile macho-o headers
#include "symmacho.hpp"
#endif
// avoid conflicts with audit.h:
#define token_t __mac_token_t
#include <sys/sysctl.h>
#include <mach-o/fat.h>
#undef token_t
class macbase_debmod_t: public BASE_DEBUGGER_MODULE
{
typedef BASE_DEBUGGER_MODULE inherited;
protected:
// return number of processes, -1 - not implemented
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf) override;
// return the file name assciated with pid
virtual bool idaapi get_exec_fname(int pid, char *buf, size_t bufsize) newapi;
// get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
virtual int idaapi get_process_bitness(int pid) newapi;
cpu_type_t get_process_cpu(pid_t pid) const;
inline int idaapi get_cpu_bitness(cpu_type_t cpu);
};
//--------------------------------------------------------------------------
inline int idaapi macbase_debmod_t::get_cpu_bitness(cpu_type_t cpu)
{
return (cpu & CPU_ARCH_ABI64) != 0 ? 8 : 4;
}
#endif

350
idasdk75/dbg/mac/makefile Normal file
View File

@@ -0,0 +1,350 @@
include ../../allmake.mak
GOALS-$(BUILD_IDA) += configs # target in $(IDA)module.mak
GOALS-$(BUILD_IDA) += modules # target in $(IDA)module.mak
GOALS-$(BUILD_DBGSRV) += server # target in $(IDA)dbg/server.mak
.PHONY: $(GOALS-1)
all: $(GOALS-1)
#----------------------------------------------------------------------
ifdef __MAC__
SERVER = mac_server$(B)
endif
ifdef SERVER
SERVERS += $(call server_exe,$(SERVER))
endif
#----------------------------------------------------------------------
STUB = $(call module_dll,mac_stub)
ifdef BUILD_IDA
MODULES += $(STUB)
endif
#----------------------------------------------------------------------
USER = $(call module_dll,mac_user)
ifeq ($(and $(BUILD_IDA),$(__MAC__)),1)
MODULES += $(USER)
CONFIGS += dbg_macosx.cfg
endif
#----------------------------------------------------------------------
# we explicitly added our module targets
NO_DEFAULT_TARGETS = 1
# NOTE: all MODULES must be defined before including plugin.mak.
include ../plugin.mak
# NOTE: target-specific rules and dependencies that use variable
# expansion to name the target (such as "$(MODULE): [...]") must
# come after including plugin.mak
#----------------------------------------------------------------------
# select OBJS common to user plugin and debugger server
BASE_OBJS-$(__MAC__) += $(F)macbase_debmod$(O)
BASE_OBJS-$(__MAC__) += $(F)mac_debmod$(O)
BASE_OBJS-$(__MAC__) += $(F)excServer$(O)
BASE_OBJS += $(BASE_OBJS-1) $(F)symmacho$(O)
$(F)symmacho$(O): CC_INCP += ../../ldr/mach-o/h $(IRRXML)
$(F)mac_debmod$(O): CC_INCP += ../../ldr/mach-o/h
excServer.c:
mig $(MACSDK)/usr/include/mach/exc.defs
ifdef __LINT__
$(F)excServer$(O):
touch $@
endif
#----------------------------------------------------------------------
SERVER_LDFLAGS += $(OUTMAP)$(F)$(@F).map
SERVER_LDFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,mac_debug$(B).plist
SERVER_STDLIBS += -framework CoreFoundation
SERVER_STDLIBS += -framework Security
# NOTE: perform the steps in mac_server_certificate.txt before using CODESIGN_MAC_SERVER!
ifdef CODESIGN_MAC_SERVER
CODESIGN_IDENTITY ?= mac_server
ifdef MAC_KEYCHAIN
CODESIGN_OPTS = --keychain $(MAC_KEYCHAIN).keychain
endif
ifdef MAC_TIMESTAMP
CODESIGN_OPTS += --timestamp=$(MAC_TIMESTAMP)
endif
ifndef __CODE_CHECKER__
SERVER_POSTACTION = $(strip codesign $(CODESIGN_OPTS) -s "$(CODESIGN_IDENTITY)" $@)
endif
endif
SERVER_OBJS += $(BASE_OBJS)
include ../server.mak
#----------------------------------------------------------------------
STUB_OBJS += $(F)mac_stub$(O)
STUB_OBJS += $(F)symmacho$(O)
$(STUB): MODULE_OBJS += $(STUB_OBJS)
$(STUB): $(STUB_OBJS)
#----------------------------------------------------------------------
USER_OBJS += $(F)mac_user$(O)
USER_OBJS += $(BASE_OBJS)
$(USER): MODULE_OBJS += $(USER_OBJS)
$(USER): $(USER_OBJS)
$(USER): STDLIBS += -framework Security
$(USER): STDLIBS += -framework CoreFoundation
#----------------------------------------------------------------------
include $(IDA)objdir.mak
# MAKEDEP dependency list ------------------
$(F)excServer$(O): ../../ldr/mach-o/h/arm/_types.h \
../../ldr/mach-o/h/i386/_types.h \
../../ldr/mach-o/h/mach/arm/boolean.h \
../../ldr/mach-o/h/mach/arm/vm_types.h \
../../ldr/mach-o/h/mach/boolean.h \
../../ldr/mach-o/h/mach/i386/boolean.h \
../../ldr/mach-o/h/mach/i386/kern_return.h \
../../ldr/mach-o/h/mach/i386/vm_param.h \
../../ldr/mach-o/h/mach/i386/vm_types.h \
../../ldr/mach-o/h/mach/kern_return.h \
../../ldr/mach-o/h/mach/machine/boolean.h \
../../ldr/mach-o/h/mach/machine/kern_return.h \
../../ldr/mach-o/h/mach/machine/vm_types.h \
../../ldr/mach-o/h/mach/message.h \
../../ldr/mach-o/h/mach/port.h \
../../ldr/mach-o/h/mach/ppc/boolean.h \
../../ldr/mach-o/h/mach/ppc/kern_return.h \
../../ldr/mach-o/h/mach/ppc/vm_param.h \
../../ldr/mach-o/h/mach/ppc/vm_types.h \
../../ldr/mach-o/h/ppc/_types.h \
../../ldr/mach-o/h/sys/_posix_availability.h \
../../ldr/mach-o/h/sys/_symbol_aliasing.h \
../../ldr/mach-o/h/sys/cdefs.h excServer.c
$(F)mac_debmod$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)diskio.hpp $(I)err.h $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
../../ldr/mach-o/common.h \
../../ldr/mach-o/h/architecture/byte_order.h \
../../ldr/mach-o/h/arm/_types.h \
../../ldr/mach-o/h/i386/_types.h \
../../ldr/mach-o/h/i386/eflags.h \
../../ldr/mach-o/h/libkern/OSByteOrder.h \
../../ldr/mach-o/h/libkern/i386/OSByteOrder.h \
../../ldr/mach-o/h/libkern/i386/_OSByteOrder.h \
../../ldr/mach-o/h/libkern/machine/OSByteOrder.h \
../../ldr/mach-o/h/mach-o/arm/reloc.h \
../../ldr/mach-o/h/mach-o/arm64/reloc.h \
../../ldr/mach-o/h/mach-o/fat.h \
../../ldr/mach-o/h/mach-o/hppa/reloc.h \
../../ldr/mach-o/h/mach-o/i860/reloc.h \
../../ldr/mach-o/h/mach-o/loader.h \
../../ldr/mach-o/h/mach-o/m88k/reloc.h \
../../ldr/mach-o/h/mach-o/nlist.h \
../../ldr/mach-o/h/mach-o/ppc/reloc.h \
../../ldr/mach-o/h/mach-o/reloc.h \
../../ldr/mach-o/h/mach-o/sparc/reloc.h \
../../ldr/mach-o/h/mach-o/stab.h \
../../ldr/mach-o/h/mach-o/x86_64/reloc.h \
../../ldr/mach-o/h/mach/arm/_structs.h \
../../ldr/mach-o/h/mach/arm/boolean.h \
../../ldr/mach-o/h/mach/arm/thread_state.h \
../../ldr/mach-o/h/mach/arm/thread_status.h \
../../ldr/mach-o/h/mach/arm/vm_types.h \
../../ldr/mach-o/h/mach/boolean.h \
../../ldr/mach-o/h/mach/i386/_structs.h \
../../ldr/mach-o/h/mach/i386/boolean.h \
../../ldr/mach-o/h/mach/i386/fp_reg.h \
../../ldr/mach-o/h/mach/i386/kern_return.h \
../../ldr/mach-o/h/mach/i386/thread_state.h \
../../ldr/mach-o/h/mach/i386/thread_status.h \
../../ldr/mach-o/h/mach/i386/vm_param.h \
../../ldr/mach-o/h/mach/i386/vm_types.h \
../../ldr/mach-o/h/mach/kern_return.h \
../../ldr/mach-o/h/mach/machine.h \
../../ldr/mach-o/h/mach/machine/boolean.h \
../../ldr/mach-o/h/mach/machine/kern_return.h \
../../ldr/mach-o/h/mach/machine/thread_status.h \
../../ldr/mach-o/h/mach/machine/vm_types.h \
../../ldr/mach-o/h/mach/message.h \
../../ldr/mach-o/h/mach/port.h \
../../ldr/mach-o/h/mach/ppc/_structs.h \
../../ldr/mach-o/h/mach/ppc/boolean.h \
../../ldr/mach-o/h/mach/ppc/kern_return.h \
../../ldr/mach-o/h/mach/ppc/thread_status.h \
../../ldr/mach-o/h/mach/ppc/vm_param.h \
../../ldr/mach-o/h/mach/ppc/vm_types.h \
../../ldr/mach-o/h/mach/shared_region.h \
../../ldr/mach-o/h/mach/vm_prot.h \
../../ldr/mach-o/h/mach/vm_types.h \
../../ldr/mach-o/h/ppc/_types.h \
../../ldr/mach-o/h/sys/_posix_availability.h \
../../ldr/mach-o/h/sys/_symbol_aliasing.h \
../../ldr/mach-o/h/sys/appleapiopts.h \
../../ldr/mach-o/h/sys/cdefs.h \
../../ldr/mach-o/h/sys/ptrace.h \
../../ldr/mach-o/macho_node.h ../deb_pc.hpp ../debmod.h \
../pc_debmod.h ../pc_regs.hpp mac_debmod.cpp \
mac_debmod.h macbase_debmod.h symmacho.hpp
$(F)mac_stub$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../../ldr/mach-o/macho_node.h ../common_local_impl.cpp \
../common_stub_impl.cpp ../dbg_rpc_client.h \
../dbg_rpc_engine.h ../deb_pc.hpp ../debmod.h \
../macho_rebase.cpp ../pc_local_impl.cpp ../pc_regs.hpp \
../rpc_debmod.h mac_local_impl.cpp mac_stub.cpp \
symmacho.hpp
$(F)mac_user$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)dbg.hpp $(I)diskio.hpp $(I)err.h $(I)expr.hpp \
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \
$(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../../ldr/mach-o/h/architecture/byte_order.h \
../../ldr/mach-o/h/arm/_types.h \
../../ldr/mach-o/h/i386/_types.h \
../../ldr/mach-o/h/libkern/OSByteOrder.h \
../../ldr/mach-o/h/libkern/i386/OSByteOrder.h \
../../ldr/mach-o/h/libkern/i386/_OSByteOrder.h \
../../ldr/mach-o/h/libkern/machine/OSByteOrder.h \
../../ldr/mach-o/h/mach-o/fat.h \
../../ldr/mach-o/h/mach-o/nlist.h \
../../ldr/mach-o/h/mach-o/reloc.h \
../../ldr/mach-o/h/mach/arm/boolean.h \
../../ldr/mach-o/h/mach/arm/vm_types.h \
../../ldr/mach-o/h/mach/boolean.h \
../../ldr/mach-o/h/mach/i386/boolean.h \
../../ldr/mach-o/h/mach/i386/vm_param.h \
../../ldr/mach-o/h/mach/i386/vm_types.h \
../../ldr/mach-o/h/mach/machine.h \
../../ldr/mach-o/h/mach/machine/boolean.h \
../../ldr/mach-o/h/mach/machine/vm_types.h \
../../ldr/mach-o/h/mach/port.h \
../../ldr/mach-o/h/mach/ppc/boolean.h \
../../ldr/mach-o/h/mach/ppc/vm_param.h \
../../ldr/mach-o/h/mach/ppc/vm_types.h \
../../ldr/mach-o/h/mach/shared_region.h \
../../ldr/mach-o/h/mach/vm_prot.h \
../../ldr/mach-o/h/mach/vm_types.h \
../../ldr/mach-o/h/ppc/_types.h \
../../ldr/mach-o/h/sys/_posix_availability.h \
../../ldr/mach-o/h/sys/_symbol_aliasing.h \
../../ldr/mach-o/h/sys/appleapiopts.h \
../../ldr/mach-o/h/sys/cdefs.h \
../../ldr/mach-o/h/sys/ptrace.h \
../../ldr/mach-o/macho_node.h ../common_local_impl.cpp \
../common_stub_impl.cpp ../deb_pc.hpp ../debmod.h \
../macho_rebase.cpp ../pc_debmod.h ../pc_local_impl.cpp \
../pc_regs.hpp mac_debmod.h mac_local_impl.cpp \
mac_user.cpp macbase_debmod.h symmacho.hpp
$(F)macbase_debmod$(O): $(I)bytes.hpp $(I)diskio.hpp $(I)fpro.h \
$(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp $(I)lines.hpp \
$(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)prodir.h $(I)range.hpp \
$(I)ua.hpp $(I)xref.hpp \
../../ldr/mach-o/h/architecture/byte_order.h \
../../ldr/mach-o/h/arm/_types.h \
../../ldr/mach-o/h/i386/_types.h \
../../ldr/mach-o/h/libkern/OSByteOrder.h \
../../ldr/mach-o/h/libkern/i386/OSByteOrder.h \
../../ldr/mach-o/h/libkern/i386/_OSByteOrder.h \
../../ldr/mach-o/h/libkern/machine/OSByteOrder.h \
../../ldr/mach-o/h/mach-o/fat.h \
../../ldr/mach-o/h/mach/arm/boolean.h \
../../ldr/mach-o/h/mach/arm/vm_types.h \
../../ldr/mach-o/h/mach/boolean.h \
../../ldr/mach-o/h/mach/i386/boolean.h \
../../ldr/mach-o/h/mach/i386/vm_param.h \
../../ldr/mach-o/h/mach/i386/vm_types.h \
../../ldr/mach-o/h/mach/machine.h \
../../ldr/mach-o/h/mach/machine/boolean.h \
../../ldr/mach-o/h/mach/machine/vm_types.h \
../../ldr/mach-o/h/mach/ppc/boolean.h \
../../ldr/mach-o/h/mach/ppc/vm_param.h \
../../ldr/mach-o/h/mach/ppc/vm_types.h \
../../ldr/mach-o/h/ppc/_types.h ../deb_pc.hpp \
../debmod.h ../pc_debmod.h ../pc_regs.hpp \
macbase_debmod.cpp macbase_debmod.h symmacho.hpp
$(F)symmacho$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)err.h \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp \
$(I)offset.hpp $(I)pro.h $(I)prodir.h $(I)range.hpp \
$(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
$(IRRXML)CXMLReaderImpl.h $(IRRXML)fast_atof.h \
$(IRRXML)heapsort.h $(IRRXML)irrArray.h \
$(IRRXML)irrString.h $(IRRXML)irrTypes.h \
$(IRRXML)irrXML.h ../../ldr/ar/aixar.hpp \
../../ldr/ar/ar.hpp ../../ldr/ar/arcmn.cpp \
../../ldr/mach-o/../ar/ar.hpp \
../../ldr/mach-o/../idaldr.h ../../ldr/mach-o/base.cpp \
../../ldr/mach-o/common.cpp ../../ldr/mach-o/common.h \
../../ldr/mach-o/dsym.cpp ../../ldr/mach-o/dsym.h \
../../ldr/mach-o/h/architecture/byte_order.h \
../../ldr/mach-o/h/arm/_types.h \
../../ldr/mach-o/h/i386/_types.h \
../../ldr/mach-o/h/i386/eflags.h \
../../ldr/mach-o/h/libkern/OSByteOrder.h \
../../ldr/mach-o/h/libkern/i386/OSByteOrder.h \
../../ldr/mach-o/h/libkern/i386/_OSByteOrder.h \
../../ldr/mach-o/h/libkern/machine/OSByteOrder.h \
../../ldr/mach-o/h/mach-o/arm/reloc.h \
../../ldr/mach-o/h/mach-o/arm64/reloc.h \
../../ldr/mach-o/h/mach-o/fat.h \
../../ldr/mach-o/h/mach-o/hppa/reloc.h \
../../ldr/mach-o/h/mach-o/i860/reloc.h \
../../ldr/mach-o/h/mach-o/loader.h \
../../ldr/mach-o/h/mach-o/m88k/reloc.h \
../../ldr/mach-o/h/mach-o/nlist.h \
../../ldr/mach-o/h/mach-o/ppc/reloc.h \
../../ldr/mach-o/h/mach-o/reloc.h \
../../ldr/mach-o/h/mach-o/sparc/reloc.h \
../../ldr/mach-o/h/mach-o/stab.h \
../../ldr/mach-o/h/mach-o/x86_64/reloc.h \
../../ldr/mach-o/h/mach/arm/_structs.h \
../../ldr/mach-o/h/mach/arm/boolean.h \
../../ldr/mach-o/h/mach/arm/thread_state.h \
../../ldr/mach-o/h/mach/arm/thread_status.h \
../../ldr/mach-o/h/mach/arm/vm_types.h \
../../ldr/mach-o/h/mach/boolean.h \
../../ldr/mach-o/h/mach/i386/_structs.h \
../../ldr/mach-o/h/mach/i386/boolean.h \
../../ldr/mach-o/h/mach/i386/fp_reg.h \
../../ldr/mach-o/h/mach/i386/kern_return.h \
../../ldr/mach-o/h/mach/i386/thread_state.h \
../../ldr/mach-o/h/mach/i386/thread_status.h \
../../ldr/mach-o/h/mach/i386/vm_param.h \
../../ldr/mach-o/h/mach/i386/vm_types.h \
../../ldr/mach-o/h/mach/kern_return.h \
../../ldr/mach-o/h/mach/kmod.h \
../../ldr/mach-o/h/mach/machine.h \
../../ldr/mach-o/h/mach/machine/boolean.h \
../../ldr/mach-o/h/mach/machine/kern_return.h \
../../ldr/mach-o/h/mach/machine/thread_status.h \
../../ldr/mach-o/h/mach/machine/vm_types.h \
../../ldr/mach-o/h/mach/message.h \
../../ldr/mach-o/h/mach/port.h \
../../ldr/mach-o/h/mach/ppc/_structs.h \
../../ldr/mach-o/h/mach/ppc/boolean.h \
../../ldr/mach-o/h/mach/ppc/kern_return.h \
../../ldr/mach-o/h/mach/ppc/thread_status.h \
../../ldr/mach-o/h/mach/ppc/vm_param.h \
../../ldr/mach-o/h/mach/ppc/vm_types.h \
../../ldr/mach-o/h/mach/vm_prot.h \
../../ldr/mach-o/h/mach/vm_types.h \
../../ldr/mach-o/h/ppc/_types.h \
../../ldr/mach-o/h/sys/_posix_availability.h \
../../ldr/mach-o/h/sys/_symbol_aliasing.h \
../../ldr/mach-o/h/sys/cdefs.h \
../../ldr/mach-o/macho_node.h ../debmod.h symmacho.cpp \
symmacho.hpp

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,249 @@
#ifndef SYMMACHO_H
#define SYMMACHO_H
// manage the mach-o images in a darwin process
#include <pro.h>
#include <idd.hpp>
#include <map>
class debmod_t;
class linput_t;
typedef std::map<ea_t, qstring> strings_cache_t;
//--------------------------------------------------------------------------
struct macho_visitor_t
{
int flags;
#define MV_UUID 0x0001 // visit uuid
#define MV_FUNCTION_STARTS 0x0002 // visit function start eas
#define MV_SYMBOLS 0x0004 // visit symbols
#define MV_SEGMENTS 0x0008 // visit segments
#define MV_SECTIONS 0x0010 // visit sections
#define MV_PLATFORM_INFO 0x0020 // visit build version info
uint32 subtype; // mh.filetype
asize_t size; // image size
sval_t slide; // ASLR slide
bytevec_t uuid; // filled if MV_UUID is set
uint32 version; // platform version
macho_visitor_t(int _flags = 0)
: flags(_flags), subtype(0), size(0), slide(0), version(0) {}
virtual void visit_function_start(ea_t /*ea*/) {}
virtual void visit_symbol(ea_t /*ea*/, const char * /*name*/) {}
virtual void visit_segment(ea_t /*start*/, ea_t /*end*/, const qstring & /*name*/, bool /*is_code*/) {}
virtual void visit_section(ea_t /*start*/, ea_t /*end*/, const qstring & /*sect*/, const qstring & /*seg*/, bool /*is_code*/) {}
// called when function start info could not be found/loaded
virtual void handle_function_start_error() {}
// called just before a symbol is visited when cpu is CPU_TYPE_ARM
virtual void handle_thumb(ea_t /*ea*/, const char * /*name*/, bool /*is_thumb*/) {}
DEFINE_VIRTUAL_DTOR(macho_visitor_t)
};
//--------------------------------------------------------------------------
class macho_utils_t
{
public:
debmod_t *dbgmod;
int arch; // PLFM_386 or PLFM_ARM
int addrsize; // size of an address in the target process
bool is64; // is target process 64-bit?
bool warned; // warned the user about using SYMBOL_PATH when remote debugging
// sometimes macho images might share a common string table. ensure the same string table isn't loaded twice.
strings_cache_t strcache;
macho_utils_t(debmod_t *_dbgmod, int _arch);
DEFINE_VIRTUAL_DTOR(macho_utils_t)
virtual void clear(void);
int get_cputype(void) const;
void update_bitness(void);
size_t read_mem(ea_t ea, void *buf, size_t size);
bool read(ea_t ea, void *buf, size_t size) { return read_mem(ea, buf, size) == size; }
void get_ptr_value(ea_t *val, const uchar *buf) const;
bool is_exe_header(ea_t base);
virtual bool parse_macho_file(const char *path, ea_t base, macho_visitor_t &mv, const bytevec_t &uuid) const;
virtual bool parse_macho_input(linput_t *li, ea_t base, macho_visitor_t &mv) const;
virtual bool parse_macho_mem(ea_t base, macho_visitor_t &mv, uint32 hints = 0);
linput_t *create_mem_input(ea_t base);
bool calc_macho_uuid(bytevec_t *uuid, linput_t *li) const;
bool match_macho_uuid(linput_t *li, const bytevec_t &uuid) const;
bool calc_image_info(uint32 *subtype, asize_t *size, bytevec_t *uuid, ea_t base);
bool calc_image_info(uint32 *subtype, asize_t *size, bytevec_t *uuid, const char *path) const;
bool calc_image_info(uint32 *subtype, asize_t *size, bytevec_t *uuid, linput_t *li, ea_t base) const;
static qstring expand_home_dir(const char *path);
static void merge(
meminfo_vec_t &res,
const meminfo_vec_t &low,
const meminfo_vec_t &high);
};
//--------------------------------------------------------------------------
struct dyld_all_image_infos_t
{
uint32 version;
uint32 num_info;
ea_t info_array;
ea_t dyld_notify;
ea_t dyld_image_load_address;
ea_t dyld_image_infos_address;
ea_t shared_cache_slide;
ea_t shared_cache_base_address;
dyld_all_image_infos_t() { clear(); }
void clear();
};
//--------------------------------------------------------------------------
enum dyld_image_mode_t
{
DYLD_IMAGE_ERROR = -1,
DYLD_IMAGE_ADDING = 0,
DYLD_IMAGE_REMOVING = 1,
DYLD_IMAGE_INFO_CHANGE = 2,
};
//--------------------------------------------------------------------------
struct dll_visitor_t
{
virtual void visit_dll(
ea_t base,
asize_t size,
const char *name,
const bytevec_t &uuid) = 0;
DEFINE_VIRTUAL_DTOR(dll_visitor_t)
};
//--------------------------------------------------------------------------
struct dyld_cache_visitor_t
{
int flags;
#define DCV_MAPPINGS 0x1 // visit shared region mappings
dyld_cache_visitor_t(int _flags) : flags(_flags) {}
virtual void visit_mapping(ea_t /*start_ea*/, ea_t /*end_ea*/) {}
};
//--------------------------------------------------------------------------
class dyld_utils_t : public macho_utils_t
{
typedef macho_utils_t inherited;
template<typename H> bool is_dyld_header(ea_t base, char *filename, size_t namesize, uint32 magic);
bool is_dyld_header_64(ea_t base, char *filename, size_t namesize);
bool is_dyld_header_32(ea_t base, char *filename, size_t namesize);
public:
ea_t base_ea; // base address of dyld ifself
ea_t entry_ea; // dyld's entry point
ea_t infos_ea; // address of _dyld_all_image_infos
ea_t ranges_ea; // address of _dyld_shared_cache_ranges
dyld_all_image_infos_t infos;
rangeset_t shared_cache_ranges;
qstring symbol_path;
dyld_utils_t(debmod_t *_dbgmod, int _arch);
DEFINE_VIRTUAL_DTOR(dyld_utils_t)
virtual void clear(void) override;
bool is_shared_cache_lib(ea_t base) const { return shared_cache_ranges.contains(base); }
bool is_system_lib(ea_t base) const { return base == base_ea || is_shared_cache_lib(base); }
bool is_dyld_header(ea_t base, char *filename, size_t namesize);
bool update_infos(void);
bool update_ranges(void);
virtual bool parse_macho_mem(ea_t base, macho_visitor_t &mv, uint32 hints = 0) override;
bool parse_info_array(uint32 count, ea_t info_array, dll_visitor_t &dv);
bool parse_dyld_cache_header(dyld_cache_visitor_t &dcv);
bool untag(ea_t *ea) const;
bool get_symbol_file_path(qstring *path, const char *module) const;
bool parse_local_symbol_file(
ea_t base,
const char *module,
const bytevec_t &uuid,
macho_visitor_t &mv);
};
struct kext_info_t
{
uint64 off;
bytevec_t uuid;
};
DECLARE_TYPE_AS_MOVABLE(kext_info_t);
typedef qvector<kext_info_t> kext_info_vec_t;
//--------------------------------------------------------------------------
class kernel_utils_t : public macho_utils_t
{
typedef macho_utils_t inherited;
qstring kdk_path; // path to a Kernel Development Kit
linput_t *kcache_li; // if a kernelcache is present in the KDK, we can use it to parse kexts
uint64 prelink_data_off; // offset of __PRELINK_DATA, required for parsing prelinked kexts
kext_info_vec_t prelinked_kexts; // associate each kext's UUID with its offset in the kernelcache
uint64 find_kext_offset(const bytevec_t &uuid) const;
public:
kernel_utils_t(debmod_t *_dbgmod, int _arch)
: inherited(_dbgmod, _arch), kcache_li(NULL), prelink_data_off(0) {}
virtual ~kernel_utils_t(void) { kernel_utils_t::clear(); }
virtual void clear(void) override;
void set_kdk_path(const qstring &path);
// detect if a kernelcache is present and collect the prelinked kext info
bool parse_kcache(const bytevec_t &kernel_uuid);
// apply the given visitor to a matching kext in the kernelcache
bool parse_prelinked_kext(macho_visitor_t &mv, ea_t base, const bytevec_t &uuid);
#define KDK_SEARCH_DEFAULT 0x0 // look for any matching binary
#define KDK_SEARCH_DSYM 0x1 // look for a binary with a companion dSYM
#define KDK_SEARCH_KCACHE 0x2 // look for a kernelcache
// get the path to a matching binary in the KDK
bool find_kdk_file(
qstring *path,
int cpu_subtype,
const bytevec_t &uuid,
const char *name,
uint32 flags = KDK_SEARCH_DEFAULT) const;
// check if the given kext appears in the KDK, either as a standalone binary
// or as a prelinked kext in a kernelcache
bool find_kext(const bytevec_t &uuid, const char *kext_name) const;
};
#endif // SYMMACHO_H

View File

@@ -0,0 +1,197 @@
#include "../ldr/mach-o/macho_node.h"
//--------------------------------------------------------------------------
static bool rebase_scattered_segments(ea_t base)
{
netnode node;
node.create(MACHO_NODE);
// detect if the code and data segments have moved relative to each other.
// if so, we cannot simply apply a uniform delta to the entire database.
// we must rebase one segment at a time.
ea_t ldr_data = 0;
ea_t ldr_text = 0;
if ( node.hashval("__DATA", &ldr_data, sizeof(ldr_data), SEGM_TAG) == -1
|| node.hashval("__TEXT", &ldr_text, sizeof(ldr_text), SEGM_TAG) == -1 )
{
return false;
}
ea_t dbg_data = g_dbgmod.dbg_get_segm_start(base, "__DATA");
ea_t dbg_text = g_dbgmod.dbg_get_segm_start(base, "__TEXT");
if ( dbg_data == BADADDR || dbg_text == BADADDR )
return false;
adiff_t slide = (dbg_data - dbg_text) - (ldr_data - ldr_text);
if ( slide == 0 )
return false;
scattered_image_t si;
// we have detected segment scattering.
// ensure that we can collect the vmaddr for each loader segment in IDA.
if ( g_dbgmod.dbg_get_scattered_image(si, base) <= 0 )
return false;
uint8 ubuf[16];
bytevec_t uuid;
// it is quite possible that the input file does not match the image in the cache.
// if there is a mismatch we warn the user.
if ( !g_dbgmod.dbg_get_image_uuid(&uuid, base)
|| uuid.size() != sizeof(ubuf)
|| node.supval(MACHO_ALT_UUID, ubuf, sizeof(ubuf)) <= 0
|| memcmp(uuid.begin(), ubuf, sizeof(ubuf)) != 0 )
{
warning("AUTOHIDE DATABASE\n"
"UUID mismatch between the input file and the image in memory.\n"
"\n"
"This could mean your dyld_shared_cache is out of sync with the library on disk,\n"
"and the database will likely not be rebased properly.\n"
"\n"
"To ensure proper rebasing, please confirm that the input file was included\n"
"the last time update_dyld_shared_cache was run.\n");
}
// adjust any pointers between the code and data segments
show_wait_box("Rebasing CODE -> DATA pointers");
// we want to patch pointers in the database without writing to debugger memory
lock_dbgmem_config();
for ( nodeidx_t nidx = node.charfirst(CODE_TAG);
nidx != BADNODE && !user_cancelled();
nidx = node.charnext(nidx, CODE_TAG) )
{
ea_t ea = node2ea(nidx);
uchar kind = node.charval_ea(ea, CODE_TAG);
switch ( kind )
{
case 1: // 32-bit pointer
add_dword(ea, slide);
break;
case 2: // 64-bit pointer
add_qword(ea, slide);
break;
default: // TODO: there are many more. we will deal with them later
break;
}
}
replace_wait_box("Rebasing DATA -> CODE pointers");
for ( nodeidx_t nidx = node.charfirst(DATA_TAG);
nidx != BADNODE && !user_cancelled();
nidx = node.charnext(nidx, DATA_TAG) )
{
ea_t ea = node2ea(nidx);
uchar kind = node.charval_ea(ea, DATA_TAG);
switch ( kind )
{
case 1: // pointer
if ( inf_is_64bit() )
add_qword(ea, -slide);
else
add_dword(ea, -slide);
break;
default: // TODO: there a few more. we will deal with them later
break;
}
}
hide_wait_box();
unlock_dbgmem_config();
qvector<segment_t *> ldrsegs;
// we must collect all the loader segments before we start calling move_segm().
// this is to avoid altering the areacb_t as we're iterating over it.
for ( segment_t *s=get_first_seg(); s != NULL; s=get_next_seg(s->start_ea) )
{
if ( s->is_loader_segm() )
ldrsegs.push_back(s);
}
show_wait_box("Rebasing scattered segments");
bool ok = true;
size_t ls_count = ldrsegs.size();
size_t ss_count = si.size();
// rebase each loader segment according to its matching segment in the scattered image.
// currently we require the list of scattered segments and the list of loader segments
// to have the exact same ordering. this is because we have no way to uniquely match a
// loader segment and a scattered segment without some context. the segment's name, start_ea,
// type, and selector are all not sufficient in this situation.
for ( size_t i = 0; i < ls_count && !user_cancelled(); i++ )
{
segment_t *s = ldrsegs[i];
qstring name;
get_segm_name(&name, s);
ea_t rebase_to = 0;
if ( i < ss_count && name == si[i].name )
{
// found the loader segment in memory. rebase it to this address.
rebase_to = si[i].start_ea;
}
else if ( name == "UNDEF" )
{
// UNDEF segment is not actually in memory. just rebase it along with the other data segments.
rebase_to = s->start_ea + (dbg_data - ldr_data);
}
else
{
msg("%a: Failed to find segment %s in process memory!\n", s->start_ea, name.c_str());
ok = false;
break;
}
if ( s->start_ea != rebase_to )
{
replace_wait_box("Moving segment %s to %#a", name.c_str(), rebase_to);
int code = move_segm(s, rebase_to, MSF_PRIORITY|MSF_SILENT);
if ( code != MOVE_SEGM_OK )
{
msg("%a: Failed to rebase segment %s to %a, code=%d\n", s->start_ea, name.c_str(), rebase_to, code);
ok = false;
}
}
}
hide_wait_box();
set_imagebase(base);
node.altset(MACHO_ALT_IMAGEBASE, base);
// update segm eas in the database
qstring idx;
for ( ssize_t s = node.hashfirst(&idx, SEGM_TAG);
s >= 0;
s = node.hashnext(&idx, idx.c_str(), SEGM_TAG) )
{
ea_t start = g_dbgmod.dbg_get_segm_start(base, idx.c_str());
if ( start != BADADDR )
node.hashset(idx.c_str(), &start, sizeof(start), SEGM_TAG);
}
if ( !ok )
{
char buf[QMAXPATH];
dbg_get_input_path(buf, sizeof(buf));
warning("AUTOHIDE DATABASE\n"
"Some loader segments were not rebased properly.\n"
"\n"
"This error might occur if you are debugging a dylib from /System/Library or /usr/lib,\n"
"since these files have different segment info when they are loaded from dyld_shared_cache.\n"
"\n"
"To ensure more accurate segment info when debugging, you can:\n"
"\n"
" 1. open the dyld_shared_cache in IDA (usually found in /var/db/dyld/)\n"
" 2. select the 'Apple DYLD cache (single module)' option\n"
" 3. select %s from the list of modules\n"
" 4. use %s as the input file path in the Process Options dialog\n", qbasename(buf), buf);
}
return true;
}

60
idasdk75/dbg/makefile Normal file
View File

@@ -0,0 +1,60 @@
include ../allmake.mak
# the following platforms only build the servers, and not the plugins.
ifneq ($(or $(__ANDROID__),$(__ANDROID_X86__),$(__ARMLINUX__),$(USE_STATIC_RUNTIME)),1)
DBG_PLUGIN = $(L)dbg_plugin$(A)
CONFIGS += exceptions.cfg
endif
BASE_LIBS += $(L)dbg_rpc$(A)
BASE_LIBS += $(L)dbg_server$(A)
BASE_LIBS += $(DBG_PLUGIN)
BASE_LIBS += $(L)dbg_proc$(A)
GOALS += $(addprefix $(C),$(CONFIGS))
ALLDIRS += linux
# ALLDIRS += mac
ALLDIRS += win32
# default target
all: $(ALLDIRS) $(GOALS)
# dependencies
$(ALLDIRS): $(BASE_LIBS)
# recipes for subdirs
.PHONY: $(ALLDIRS)
$(sort $(ALLDIRS)):
$(Q)$(MAKE) -C $@
clean::
$(foreach dir,$(ALLDIRS),$(MAKE) -C $(dir) clean;)
#----------------------------------------------------------------------
RPC_OBJS += $(F)dbg_rpc_engine$(O)
RPC_OBJS += $(F)dbg_rpc_hlp$(O)
$(L)dbg_rpc$(A): $(call lib, $(RPC_OBJS))
#----------------------------------------------------------------------
SERVER_OBJS += $(F)bin_search$(O)
SERVER_OBJS += $(F)dbg_rpc_handler$(O)
SERVER_OBJS += $(F)debmod$(O)
SERVER_OBJS += $(F)server$(O)
$(L)dbg_server$(A): $(call lib, $(SERVER_OBJS))
#----------------------------------------------------------------------
PLUGIN_OBJS += $(F)bin_search$(O)
PLUGIN_OBJS += $(F)dbg_rpc_client$(O)
PLUGIN_OBJS += $(F)debmod$(O)
PLUGIN_OBJS += $(F)rpc_debmod$(O)
$(L)dbg_plugin$(A): $(call lib, $(PLUGIN_OBJS))
#----------------------------------------------------------------------
PROC_OBJS += $(F)arm_debmod$(O)
PROC_OBJS += $(F)arm_regs$(O)
PROC_OBJS += $(F)pc_debmod$(O)
PROC_OBJS += $(F)pc_regs$(O)
$(L)dbg_proc$(A): $(call lib, $(PROC_OBJS))
include $(IDA)objdir.mak

304
idasdk75/dbg/pc_debmod.cpp Normal file
View File

@@ -0,0 +1,304 @@
#ifdef __NT__
#include <windows.h>
#endif
#include <pro.h>
#include <ua.hpp>
#include "pc_debmod.h"
//--------------------------------------------------------------------------
//lint -esym(1566,pc_debmod_t::hwbpt_ea,pc_debmod_t::hwbpt_type)
//lint -esym(1566,pc_debmod_t::dr6,pc_debmod_t::dr7)
pc_debmod_t::pc_debmod_t()
{
static const uchar bpt[] = X86_BPT_CODE;
bpt_code.append(bpt, sizeof(bpt));
sp_idx = R_ESP;
pc_idx = R_EIP;
sr_idx = R_EFLAGS;
fs_idx = R_FS;
gs_idx = R_GS;
cs_idx = R_CS;
ds_idx = R_DS;
es_idx = R_ES;
ss_idx = R_SS;
nregs = X86_NREGS;
cleanup_hwbpts();
set_platform(get_local_platform());
}
//--------------------------------------------------------------------------
int pc_debmod_t::get_regidx(const char *regname, int *clsmask)
{
return x86_get_regidx(clsmask, regname);
}
//--------------------------------------------------------------------------
int idaapi pc_debmod_t::dbg_is_ok_bpt(bpttype_t type, ea_t ea, int /* len */)
{
if ( type == BPT_SOFT )
return BPT_OK;
return find_hwbpt_slot(ea, type) == -1 ? BPT_TOO_MANY : BPT_OK;
}
//--------------------------------------------------------------------------
// returns -1 if something is wrong
int pc_debmod_t::find_hwbpt_slot(ea_t ea, bpttype_t type) const
{
for ( int i=0; i < MAX_BPT; i++ )
{
if ( hwbpt_ea[i] == ea && hwbpt_type[i] == type ) // another breakpoint is here
return -1;
if ( hwbpt_ea[i] == BADADDR ) // empty slot found
return i;
}
return -1;
}
//--------------------------------------------------------------------------
bool pc_debmod_t::add_hwbpt(bpttype_t type, ea_t ea, int len)
{
int i = find_hwbpt_slot(ea, type); // get slot number
if ( i != -1 )
{
hwbpt_ea[i] = ea;
hwbpt_type[i] = type;
if ( type == BPT_EXEC )
type = 0; // exec bpts are encoded with 0 on x86
// length code used by the processor
int lenc = (len == 2) ? 1
: (len == 4) ? 3
: (len == 8) ? 2
: 0;
dr7 |= (1 << (i*2)); // enable local breakpoint
dr7 |= (type << (16+(i*4))); // set breakpoint type
dr7 |= (lenc << (18+(i*4))); // set breakpoint length
return refresh_hwbpts();
}
return false;
}
//--------------------------------------------------------------------------
bool pc_debmod_t::del_hwbpt(ea_t ea, bpttype_t type)
{
for ( int i=0; i < MAX_BPT; i++ )
{
if ( hwbpt_ea[i] == ea && hwbpt_type[i] == type )
{
hwbpt_ea[i] = BADADDR; // clean the address
dr7 &= ~(3 << (i*2)); // clean the enable bits
dr7 &= ~(0xF << (i*4+16)); // clean the length and type
return refresh_hwbpts();
}
}
return false;
}
#ifdef __NT__
//--------------------------------------------------------------------------
// Set hardware breakpoint for one thread
bool pc_debmod_t::set_hwbpts(HANDLE hThread)
{
// sure_suspend_thread(ti);
CONTEXT Context;
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_CONTROL;
BOOL ok = GetThreadContext(hThread, &Context);
if ( !ok )
{
deberr("GetThreadContext");
return false;
}
Context.Dr0 = hwbpt_ea[0];
Context.Dr1 = hwbpt_ea[1];
Context.Dr2 = hwbpt_ea[2];
Context.Dr3 = hwbpt_ea[3];
Context.Dr6 = 0;
Context.Dr7 = dr7;
ok = SetThreadContext(hThread, &Context);
if ( !ok )
{
deberr("SetThreadContext");
}
// sure_resume_thread(ti);
return ok != FALSE;
}
//--------------------------------------------------------------------------
ea_t pc_debmod_t::is_hwbpt_triggered(thid_t id, bool is_stepping)
{
CONTEXT Context;
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_CONTROL;
HANDLE h = get_thread_handle(id);
if ( GetThreadContext(h, &Context) )
{
for ( int i=0; i < MAX_BPT; i++ )
{
if ( (Context.Dr7 & uint32(1 << (i*2)))
&& (Context.Dr6 & uint32(1 << i)) ) // Local hardware breakpoint 'i'
{
ULONG_PTR *dr = NULL;
switch ( i )
{
case 0: dr = &Context.Dr0; break;
case 1: dr = &Context.Dr1; break;
case 2: dr = &Context.Dr2; break;
case 3: dr = &Context.Dr3; break;
}
if ( dr == NULL )
break;
if ( hwbpt_ea[i] == *dr )
{
set_hwbpts(h); // Clear the status bits
// do not report exec breakpoint if it occurs while we are stepping
if ( is_stepping && hwbpt_type[i] == BPT_EXEC )
break;
return hwbpt_ea[i];
}
//? TRACING else
// debdeb("System hardware breakpoint at %08X ???\n", *dr); //?
// what to do ?:
// reset it, and continue as if no event were received ?
// send it to IDA, and let the user setup a "stop on non-debugger hardware breakpoint" option ?
}
}
}
return BADADDR;
}
#endif // ifdef __NT__
//--------------------------------------------------------------------------
void pc_debmod_t::cleanup_hwbpts()
{
for ( int i=0; i < MAX_BPT; i++ )
{
hwbpt_ea[i] = BADADDR;
hwbpt_type[i] = bpttype_t(0);
}
dr6 = 0;
dr7 = 0x100; // exact local breakpoints
}
//--------------------------------------------------------------------------
ea_t pc_debmod_t::calc_appcall_stack(const regvals_t &regvals)
{
ea_t ea = inherited::calc_appcall_stack(regvals);
#ifndef __X86__
// do not touch the red zone (used by gcc)
ea = ea > 128 ? ea - 128 : BADADDR;
#endif
return ea;
}
//--------------------------------------------------------------------------
int pc_debmod_t::finalize_appcall_stack(
call_context_t &,
regval_map_t &,
bytevec_t &stk)
{
// pc-specific: add endless loop, so user does not execute unwanted code
// after manual appcall. we do not really need to write bpt,
// but it is easy to include it here than skip it.
// previously we reserved 'addrsize' bytes on the stack for this purpose,
// and we use 3 of them.
static const uchar bpt_and_loop[] = { 0xCC, 0xEB, 0xFE };
stk.append(bpt_and_loop, sizeof(bpt_and_loop));
return 0;
}
//--------------------------------------------------------------------------
bool pc_debmod_t::should_stop_appcall(
thid_t tid,
const debug_event_t *event,
ea_t ea)
{
if ( inherited::should_stop_appcall(tid, event, ea) )
return true;
// Check if the current instruction is a "RET" and then dereferences
// the contents of SP to find the return address. IF it matches, it is
// time to stop
regvals_t regs;
regs.resize(X86_NREGS);
do
{
// Start by reading registers
if ( dbg_read_registers(tid, X86_RC_GENERAL, regs.begin(), NULL) != DRC_OK )
break;
// Get the opcodes
uchar opcode;
if ( dbg_read_memory((ea_t)regs[pc_idx].ival, &opcode, 1, NULL) != 1 )
break;
// Check for "RET" and "RET n"
if ( opcode != 0xC3 && opcode != 0xC2 )
break;
// Dereference value at ESP
ea_t at_sp = BADADDR;
if ( dbg_read_memory((ea_t)regs[sp_idx].ival, &at_sp, sizeof(at_sp), NULL) != sizeof(at_sp) )
break;
return ea == at_sp; // time to stop!
} while ( false );
return false;
}
//--------------------------------------------------------------------------
bool pc_debmod_t::preprocess_appcall_cleanup(thid_t, call_context_t &ctx)
{
// Linux 2.6.24-19 has a bug(?):
// it doesn't clear trace flag after single-stepping
// so if we single-step and then make an appcall, we would restore eflags with TF set
// but next time we resume the program, kernel thinks that TF was set by the user
// and doesn't clear it, and so our appcall stops immediately
// to prevent that, we'll always clear trace flag before restoring eflags
if ( ctx.saved_regs.size() > sr_idx )
ctx.saved_regs[sr_idx].ival &= ~0x100;
return true; // success
}
//--------------------------------------------------------------------------
void pc_debmod_t::read_fpu_registers(
regval_t *values,
int clsmask,
const void *fptr,
size_t step)
{
const uchar *vptr = (const uchar *)fptr;
for ( int i=0; i < 8; i++,vptr+=step )
{
if ( (clsmask & X86_RC_FPU) != 0 )
{
regval_t *v = &values[R_ST0+i];
memcpy(v->fval, vptr, 10); //-V512 v->fval underflow
v->rvtype = RVT_FLOAT;
}
if ( (clsmask & X86_RC_MMX) != 0 )
values[R_MMX0+i].set_bytes(vptr, 8);
}
}
//--------------------------------------------------------------------------
const char *pc_debmod_t::get_local_platform()
{
#ifdef __NT__
# define LOCAL_PLATFORM "win32"
#else
# ifdef __MAC__
# define LOCAL_PLATFORM "macosx"
# else
# ifdef __LINUX__
# define LOCAL_PLATFORM "linux"
# else
# define LOCAL_PLATFORM "PC_UNDEFINED"
# endif
# endif
#endif
return LOCAL_PLATFORM;
}

52
idasdk75/dbg/pc_debmod.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef __PC_DEBUGGER_MODULE__
#define __PC_DEBUGGER_MODULE__
#ifdef __NT__
# include <windows.h>
#endif
#include "pc_regs.hpp"
#include "deb_pc.hpp"
#include "debmod.h"
class pc_debmod_t: public debmod_t
{
typedef debmod_t inherited;
protected:
// Hardware breakpoints
ea_t hwbpt_ea[MAX_BPT];
bpttype_t hwbpt_type[MAX_BPT];
uint32 dr6;
uint32 dr7;
int sr_idx;
int fs_idx;
int gs_idx;
int cs_idx;
int ds_idx;
int es_idx;
int ss_idx;
public:
pc_debmod_t();
void cleanup_hwbpts();
virtual bool refresh_hwbpts() newapi { return false; }
int find_hwbpt_slot(ea_t ea, bpttype_t type) const;
bool del_hwbpt(ea_t ea, bpttype_t type);
bool add_hwbpt(bpttype_t type, ea_t ea, int len);
static const char *get_local_platform();
#ifdef __NT__
virtual bool set_hwbpts(HANDLE hThread) newapi;
ea_t is_hwbpt_triggered(thid_t id, bool is_stepping);
virtual HANDLE get_thread_handle(thid_t /*tid*/) newapi { return INVALID_HANDLE_VALUE; }
#endif
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) override;
virtual int finalize_appcall_stack(call_context_t &, regval_map_t &, bytevec_t &stk) override;
virtual ea_t calc_appcall_stack(const regvals_t &regvals) override;
virtual bool should_stop_appcall(thid_t tid, const debug_event_t *event, ea_t ea) override;
virtual bool preprocess_appcall_cleanup(thid_t tid, call_context_t &ctx) override;
virtual int get_regidx(const char *regname, int *clsmask) override;
static void read_fpu_registers(regval_t *values, int clsmask, const void *fptr, size_t step);
};
#endif

View File

@@ -0,0 +1,113 @@
// x86-specific code (compiled only on IDA side, never on the server side)
#include <dbg.hpp>
#include "pc_regs.hpp"
#include "deb_pc.hpp"
//--------------------------------------------------------------------------
//
// DEBUGGER REGISTER AND INSTRUCTION INFORMATIONS
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
#if 0
static void DEBUG_REGVALS(regval_t *values)
{
for ( int i = 0; i < qnumber(registers); i++ )
{
msg("%s = ", registers[i].name);
switch ( registers[i].dtyp )
{
case dt_qword: msg("%016LX\n", values[i].ival); break;
case dt_dword: msg("%08X\n", values[i].ival); break;
case dt_word: msg("%04X\n", values[i].ival); break;
case dt_tbyte:
for ( int j = 0; j < sizeof(regval_t); j++ )
{
if ( j == 10 )
msg(" - "); // higher bytes are not used by x86 floats
msg("%02X ", ((unsigned char*)&values[i])[j]);
}
// msg("%02X ", (unsigned short)values[i].fval[j]);
msg("\n");
break;
}
}
msg("\n");
}
#endif
//--------------------------------------------------------------------------
drc_t idaapi x86_read_registers(
thid_t thread_id,
int clsmask,
regval_t *values,
qstring *errbuf)
{
drc_t drc = s_read_registers(thread_id, clsmask, values, errbuf);
if ( drc == DRC_OK )
{
// FPU related registers
if ( (clsmask & X86_RC_FPU) != 0 )
{
for ( size_t i = 0; i < debugger.nregs; i++ )
{
const register_info_t &ri = debugger.regs(i);
if ( ri.register_class == X86_RC_FPU && ri.dtype == dt_tbyte )
{
int rc = processor_t::realcvt(values[i].fval, values[i].fval, 004); // // load long double
if ( rc == 0 )
break; // realcvt not implemented
else if ( rc < 0 ) // error
memset(values[i].fval, 0, sizeof(values[i].fval));
}
}
}
}
return drc;
}
//--------------------------------------------------------------------------
drc_t idaapi x86_write_register(
thid_t thread_id,
int reg_idx,
const regval_t *value,
qstring *errbuf)
{
regval_t rv = *value;
// FPU related registers
const register_info_t &ri = debugger.regs(reg_idx);
if ( ri.register_class == X86_RC_FPU && ri.dtype == dt_tbyte )
{
uchar fn[10];
int code = processor_t::realcvt(fn, rv.fval, 014); // store long double //-V536 octal
if ( code == 1 )
memcpy(rv.fval, fn, 10); //-V512 rv.fval underflow
}
return s_write_register(thread_id, reg_idx, &rv, errbuf);
}
//--------------------------------------------------------------------------
int is_x86_valid_bpt(bpttype_t type, ea_t ea, int len)
{
if ( type != BPT_SOFT )
{
if ( (debugger.flags & DBG_FLAG_ANYSIZE_HWBPT) == 0 )
return check_x86_hwbpt(type, ea, len);
if ( type == 0 )
return BPT_BAD_TYPE;
}
return BPT_OK;
}
//--------------------------------------------------------------------------
void processor_specific_init(void)
{
}
//--------------------------------------------------------------------------
void processor_specific_term(void)
{
}

329
idasdk75/dbg/pc_regs.cpp Normal file
View File

@@ -0,0 +1,329 @@
#include "pc_regs.hpp"
//-------------------------------------------------------------------------
// NOTE: keep in sync with register_class_x86_t
const char *x86_register_classes[] =
{
"General registers",
"Segment registers",
"FPU registers",
"MMX registers",
"XMM registers",
"YMM registers",
NULL
};
//-------------------------------------------------------------------------
static const char *const eflags[] =
{
"CF", // 0
NULL, // 1
"PF", // 2
NULL, // 3
"AF", // 4
NULL, // 5
"ZF", // 6
"SF", // 7
"TF", // 8
"IF", // 9
"DF", // 10
"OF", // 11
"IOPL", // 12
"IOPL", // 13
"NT", // 14
NULL, // 15
"RF", // 16
"VM", // 17
"AC", // 18
"VIF", // 19
"VIP", // 20
"ID", // 21
NULL, // 22
NULL, // 23
NULL, // 24
NULL, // 25
NULL, // 26
NULL, // 27
NULL, // 28
NULL, // 29
NULL, // 30
NULL // 31
};
//-------------------------------------------------------------------------
static const char *const ctrlflags[] =
{
"CTRL.IM",
"CTRL.DM",
"CTRL.ZM",
"CTRL.OM",
"CTRL.UM",
"CTRL.PM",
NULL,
NULL,
"CTRL.PC",
"CTRL.PC",
"CTRL.RC",
"CTRL.RC",
"CTRL.X",
NULL,
NULL,
NULL
};
//-------------------------------------------------------------------------
static const char *const statflags[] =
{
"STAT.IE",
"STAT.DE",
"STAT.ZE",
"STAT.OE",
"STAT.UE",
"STAT.PE",
"STAT.SF",
"STAT.ES",
"STAT.C0",
"STAT.C1",
"STAT.C2",
"STAT.TOP",
"STAT.TOP",
"STAT.TOP",
"STAT.C3",
"STAT.B"
};
//-------------------------------------------------------------------------
static const char *const tagsflags[] =
{
"TAG0",
"TAG0",
"TAG1",
"TAG1",
"TAG2",
"TAG2",
"TAG3",
"TAG3",
"TAG4",
"TAG4",
"TAG5",
"TAG5",
"TAG6",
"TAG6",
"TAG7",
"TAG7"
};
//-------------------------------------------------------------------------
static const char *const xmm_format[] =
{
"XMM_4_floats",
};
//-------------------------------------------------------------------------
static const char *const ymm_format[] =
{
"YMM_8_floats",
};
//-------------------------------------------------------------------------
static const char *const mmx_format[] =
{
"MMX_8_bytes",
};
//-------------------------------------------------------------------------
static const char *const mxcsr_bits[] =
{
"IE", // 0 Invalid Operation Flag
"DE", // 1 Denormal Flag
"ZE", // 2 Divide-by-Zero Flag
"OE", // 3 Overflow Flag
"UE", // 4 Underflow Flag
"PE", // 5 Precision Flag
"DAZ", // 6 Denormals Are Zeros*
"IM", // 7 Invalid Operation Mask
"DM", // 8 Denormal Operation Mask
"ZM", // 9 Divide-by-Zero Mask
"OM", // 10 Overflow Mask
"UM", // 11 Underflow Mask
"PM", // 12 Precision Mask
"RC", // 13 Rounding Control
"RC", // 14 Rounding Control
"FZ", // 15 Flush to Zero
NULL, // 16
NULL, // 17
NULL, // 18
NULL, // 19
NULL, // 20
NULL, // 21
NULL, // 22
NULL, // 23
NULL, // 24
NULL, // 25
NULL, // 26
NULL, // 27
NULL, // 28
NULL, // 29
NULL, // 30
NULL // 31
};
//-------------------------------------------------------------------------
// General registers
#ifdef __EA64__
register_info_t r_rax = { "RAX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_rbx = { "RBX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_rcx = { "RCX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_rdx = { "RDX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_rsi = { "RSI", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_rdi = { "RDI", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_rbp = { "RBP", REGISTER_ADDRESS|REGISTER_FP, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_rsp = { "RSP", REGISTER_ADDRESS|REGISTER_SP, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_rip = { "RIP", REGISTER_ADDRESS|REGISTER_IP, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_r8 = { "R8", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_r9 = { "R9", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_r10 = { "R10", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_r11 = { "R11", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_r12 = { "R12", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_r13 = { "R13", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_r14 = { "R14", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
register_info_t r_r15 = { "R15", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
#endif
register_info_t r_eax = { "EAX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
register_info_t r_ebx = { "EBX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
register_info_t r_ecx = { "ECX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
register_info_t r_edx = { "EDX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
register_info_t r_esi = { "ESI", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
register_info_t r_edi = { "EDI", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
register_info_t r_ebp = { "EBP", REGISTER_ADDRESS|REGISTER_FP, X86_RC_GENERAL, dt_dword, NULL, 0 };
register_info_t r_esp = { "ESP", REGISTER_ADDRESS|REGISTER_SP, X86_RC_GENERAL, dt_dword, NULL, 0 };
register_info_t r_eip = { "EIP", REGISTER_ADDRESS|REGISTER_IP, X86_RC_GENERAL, dt_dword, NULL, 0 };
//-------------------------------------------------------------------------
// NOTE: keep in sync with register_x86_t
register_info_t x86_registers[] =
{
// FPU registers
{ "ST0", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
{ "ST1", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
{ "ST2", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
{ "ST3", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
{ "ST4", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
{ "ST5", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
{ "ST6", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
{ "ST7", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
{ "CTRL", 0, X86_RC_FPU, dt_word, ctrlflags, 0x1F3F },
{ "STAT", 0, X86_RC_FPU, dt_word, statflags, 0xFFFF },
{ "TAGS", 0, X86_RC_FPU, dt_word, tagsflags, 0xFFFF },
// Segment registers
{ "CS", REGISTER_CS|REGISTER_NOLF, X86_RC_SEGMENTS, dt_word, NULL, 0 },
{ "DS", REGISTER_NOLF, X86_RC_SEGMENTS, dt_word, NULL, 0 },
{ "ES", 0, X86_RC_SEGMENTS, dt_word, NULL, 0 },
{ "FS", REGISTER_NOLF, X86_RC_SEGMENTS, dt_word, NULL, 0 },
{ "GS", REGISTER_NOLF, X86_RC_SEGMENTS, dt_word, NULL, 0 },
{ "SS", REGISTER_SS, X86_RC_SEGMENTS, dt_word, NULL, 0 },
// General registers
#ifdef __EA64__
r_rax,
r_rbx,
r_rcx,
r_rdx,
r_rsi,
r_rdi,
r_rbp,
r_rsp,
r_rip,
r_r8,
r_r9,
r_r10,
r_r11,
r_r12,
r_r13,
r_r14,
r_r15,
#else
r_eax,
r_ebx,
r_ecx,
r_edx,
r_esi,
r_edi,
r_ebp,
r_esp,
r_eip,
#endif
{ "EFL", 0, X86_RC_GENERAL, dt_dword, eflags, 0x00000FD5 }, // OF|DF|IF|TF|SF|ZF|AF|PF|CF
// XMM registers
{ "XMM0", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM1", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM2", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM3", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM4", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM5", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM6", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM7", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
#ifdef __EA64__
{ "XMM8", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM9", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM10", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM11", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM12", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM13", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM14", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
{ "XMM15", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
#endif
{ "MXCSR", 0, X86_RC_XMM, dt_dword, mxcsr_bits, 0xFFFF },
// MMX registers
{ "MM0", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
{ "MM1", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
{ "MM2", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
{ "MM3", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
{ "MM4", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
{ "MM5", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
{ "MM6", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
{ "MM7", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
// YMM registers
{ "YMM0", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM1", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM2", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM3", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM4", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM5", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM6", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM7", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
#ifdef __EA64__
{ "YMM8", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM9", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM10", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM11", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM12", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM13", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM14", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
{ "YMM15", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
#endif
};
CASSERT(qnumber(x86_registers) == X86_NREGS);
//-------------------------------------------------------------------------
int x86_get_regidx(int *clsmask, const char *regname)
{
for ( size_t i = 0; i < qnumber(x86_registers); i++ )
{
if ( strieq(regname, x86_registers[i].name) )
{
if ( clsmask != NULL )
*clsmask = x86_registers[i].register_class;
return i;
}
}
return -1;
}
//-------------------------------------------------------------------------
int x86_get_regclass(int idx)
{
if ( idx >= 0 && idx < qnumber(x86_registers) )
return x86_registers[idx].register_class;
return 0;
}

172
idasdk75/dbg/pc_regs.hpp Normal file
View File

@@ -0,0 +1,172 @@
#pragma once
#include <pro.h>
#include <idd.hpp>
//-------------------------------------------------------------------------
// NOTE: keep in sync with x86_register_classes
enum register_class_x86_t
{
X86_RC_GENERAL = 0x01, // General registers
X86_RC_SEGMENTS = 0x02, // Segment registers
X86_RC_FPU = 0x04, // FPU registers
X86_RC_MMX = 0x08, // MMX registers
X86_RC_XMM = 0x10, // XMM registers
X86_RC_YMM = 0x20, // YMM registers
X86_RC_ALL = X86_RC_GENERAL
| X86_RC_SEGMENTS
| X86_RC_FPU
| X86_RC_MMX
| X86_RC_XMM
| X86_RC_YMM
};
//-------------------------------------------------------------------------
// NOTE: keep in sync with x86_registers
enum register_x86_t
{
// FPU registers
R_ST0,
R_ST1,
R_ST2,
R_ST3,
R_ST4,
R_ST5,
R_ST6,
R_ST7,
R_CTRL,
R_STAT,
R_TAGS,
// Segment registers
R_CS,
R_DS,
R_ES,
R_FS,
R_GS,
R_SS,
// General registers
R_EAX,
R_EBX,
R_ECX,
R_EDX,
R_ESI,
R_EDI,
R_EBP,
R_ESP,
R_EIP,
#ifdef __EA64__
R_R8,
R_R9,
R_R10,
R_R11,
R_R12,
R_R13,
R_R14,
R_R15,
#endif
R_EFLAGS,
// XMM registers
R_XMM0,
R_XMM1,
R_XMM2,
R_XMM3,
R_XMM4,
R_XMM5,
R_XMM6,
R_XMM7,
#ifndef __EA64__
R_LAST_XMM = R_XMM7,
#else
R_XMM8,
R_XMM9,
R_XMM10,
R_XMM11,
R_XMM12,
R_XMM13,
R_XMM14,
R_XMM15,
R_LAST_XMM = R_XMM15,
#endif
R_MXCSR,
// MMX registers
R_MMX0,
R_MMX1,
R_MMX2,
R_MMX3,
R_MMX4,
R_MMX5,
R_MMX6,
R_MMX7,
// YMM registers
R_YMM0,
R_YMM1,
R_YMM2,
R_YMM3,
R_YMM4,
R_YMM5,
R_YMM6,
R_YMM7,
#ifndef __EA64__
R_LAST_YMM = R_YMM7,
#else
R_YMM8,
R_YMM9,
R_YMM10,
R_YMM11,
R_YMM12,
R_YMM13,
R_YMM14,
R_YMM15,
R_LAST_YMM = R_YMM15,
#endif
};
// Number of registers in x86 and x64
#define X86_X64_NREGS 76
#define X86_X86_NREGS 52
#ifdef __EA64__
#define X86_NREGS X86_X64_NREGS
#else
#define X86_NREGS X86_X86_NREGS
#endif
//-------------------------------------------------------------------------
// General registers
#ifdef __EA64__
extern register_info_t r_rax;
extern register_info_t r_rbx;
extern register_info_t r_rcx;
extern register_info_t r_rdx;
extern register_info_t r_rsi;
extern register_info_t r_rdi;
extern register_info_t r_rbp;
extern register_info_t r_rsp;
extern register_info_t r_rip;
extern register_info_t r_r8;
extern register_info_t r_r9;
extern register_info_t r_r10;
extern register_info_t r_r11;
extern register_info_t r_r12;
extern register_info_t r_r13;
extern register_info_t r_r14;
extern register_info_t r_r15;
#endif
extern register_info_t r_eax;
extern register_info_t r_ebx;
extern register_info_t r_ecx;
extern register_info_t r_edx;
extern register_info_t r_esi;
extern register_info_t r_edi;
extern register_info_t r_ebp;
extern register_info_t r_esp;
extern register_info_t r_eip;
//-------------------------------------------------------------------------
extern const char *x86_register_classes[];
extern register_info_t x86_registers[X86_NREGS];
//-------------------------------------------------------------------------
int x86_get_regidx(int *clsmask, const char *regname);
int x86_get_regclass(int idx);

18
idasdk75/dbg/plugin.mak Normal file
View File

@@ -0,0 +1,18 @@
ifneq ($(wildcard ../../parse),)
CC_DEFS += ENABLE_LOWCNDS
endif
CC_INCP += ..
include ../../plugins/plugin.mak
PLUGIN_LIBS += $(L)dbg_plugin$(A)
PLUGIN_LIBS += $(L)dbg_rpc$(A)
PLUGIN_LIBS += $(L)dbg_proc$(A)
PLUGIN_LIBS += $(L)network$(A)
$(MODULES): LIBS += $(PLUGIN_LIBS)
$(MODULES): $(PLUGIN_LIBS)
ifeq ($(or $(__LINUX__),$(__MAC__)),1)
$(MODULES): STDLIBS += -ldl
endif

996
idasdk75/dbg/rpc_debmod.cpp Normal file
View File

@@ -0,0 +1,996 @@
#include <segment.hpp>
#include <err.h>
#include <network.hpp>
#include "rpc_debmod.h"
#include "dbg_rpc_hlp.h"
//-------------------------------------------------------------------------
inline drc_t unpack_drc(memory_deserializer_t &mmdsr)
{
return drc_t(mmdsr.unpack_dd());
}
//--------------------------------------------------------------------------
rpc_debmod_t::rpc_debmod_t(const char *default_platform)
: dbg_rpc_client_t(NULL)
{
nregs = debugger.nregs;
for ( int i=0; i < nregs; i++ )
{
const register_info_t &ri = debugger.regs(i);
if ( (ri.flags & REGISTER_SP) != 0 )
sp_idx = i;
if ( (ri.flags & REGISTER_IP) != 0 )
pc_idx = i;
}
bpt_code.append(debugger.bpt_bytes, debugger.bpt_size);
rpc = this;
set_platform(default_platform);
}
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::handle_ioctl( //-V524 equivalent to 'send_ioctl'
int fn,
const void *buf,
size_t size,
void **poutbuf,
ssize_t *poutsize)
{
return rpc_engine_t::send_ioctl(fn, buf, size, poutbuf, poutsize);
}
//--------------------------------------------------------------------------
inline int get_expected_addrsize(void)
{
if ( is_miniidb() )
#ifdef __EA64__
return 8;
#else
return 4;
#endif
return inf_is_64bit() ? 8 : 4;
}
//--------------------------------------------------------------------------
bool idaapi rpc_debmod_t::open_remote(
const char *hostname,
int port_number,
const char *password,
qstring *errbuf)
{
if ( hostname[0] == '\0' )
{
if ( errbuf != NULL )
*errbuf = "Please specify the hostname in Debugger, Process options";
return false;
}
rpc_packet_t *rp = NULL;
network_error = false;
client_irs = irs_new();
if ( !irs_init_client(client_irs, hostname, port_number) )
{
FAILURE:
if ( rp != NULL )
qfree(rp);
if ( errbuf != NULL )
*errbuf = irs_strerror(client_irs);
irs_term(&client_irs);
return false;
}
rp = recv_packet();
if ( rp == NULL || rp->code != RPC_OPEN ) // is this an ida debugger server?
{
dbg_rpc_client_t::dwarning("ICON ERROR\nAUTOHIDE NONE\n"
"Bogus or irresponsive remote server");
goto FAILURE;
}
memory_deserializer_t mmdsr(rp+1, rp->length);
int version = mmdsr.unpack_dd();
int remote_debugger_id = mmdsr.unpack_dd();
int easize = mmdsr.unpack_dd();
qstring errstr;
if ( version != IDD_INTERFACE_VERSION )
errstr.sprnt("protocol version is %d, expected %d", version, IDD_INTERFACE_VERSION);
else if ( remote_debugger_id != debugger.id )
errstr.sprnt("debugger id is %d, expected %d (%s)", remote_debugger_id, debugger.id, debugger.name);
else if ( easize < get_expected_addrsize() )
errstr.sprnt("address size is %d bytes, expected at least %d", easize, get_expected_addrsize());
if ( !errstr.empty() )
{
bytevec_t req = prepare_rpc_packet(RPC_OK);
req.pack_dd(false);
send_data(req);
warning("ICON ERROR\nAUTOHIDE NONE\n"
"Incompatible debugging server:\n"
"%s", errstr.c_str());
goto FAILURE;
}
qfree(rp);
bytevec_t req = prepare_rpc_packet(RPC_OK);
req.pack_dd(true);
req.pack_str(password);
send_data(req);
rp = recv_packet();
if ( rp == NULL || rp->code != RPC_OK )
goto FAILURE;
memory_deserializer_t mmdsr2(rp+1, rp->length);
bool password_ok = mmdsr2.unpack_dd() != 0;
if ( !password_ok ) // is this an ida debugger server?
{
warning("ICON ERROR\nAUTOHIDE NONE\n"
"Bad password");
goto FAILURE;
}
qfree(rp);
return true;
}
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::dbg_add_bpt(bytevec_t *, bpttype_t, ea_t, int)
{
INTERR(30114);
}
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::dbg_del_bpt(bpttype_t, ea_t, const uchar *, int)
{
INTERR(30115);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_update_lowcnds(
int *nupdated,
const lowcnd_t *lowcnds,
int nlowcnds,
qstring *errbuf)
{
ea_t ea = 0;
bytevec_t req = prepare_rpc_packet(RPC_UPDATE_LOWCNDS);
req.pack_dd(nlowcnds);
const lowcnd_t *lc = lowcnds;
for ( int i=0; i < nlowcnds; i++, lc++ )
{
req.pack_ea64(lc->ea-ea); ea = lc->ea;
req.pack_str(lc->cndbody);
if ( !lc->cndbody.empty() )
{
req.pack_dd(lc->type);
if ( lc->type != BPT_SOFT )
req.pack_dd(lc->size);
req.pack_db(lc->orgbytes.size());
req.append(lc->orgbytes.begin(), lc->orgbytes.size());
req.pack_ea64(lc->cmd.ea);
if ( lc->cmd.ea != BADADDR )
req.append(&lc->cmd, sizeof(lc->cmd));
}
}
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = unpack_drc(mmdsr);
int ret_nupdated = mmdsr.unpack_dd();
if ( nupdated != NULL )
*nupdated = ret_nupdated;
if ( errbuf != NULL && drc != DRC_NONE )
*errbuf = mmdsr.unpack_str();
qfree(rp);
return drc;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_EVAL_LOWCND);
req.pack_dd(tid);
req.pack_ea64(ea);
return send_request_get_drc_result(req, errbuf);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_update_bpts(
int *nbpts,
update_bpt_info_t *ubpts,
int nadd,
int ndel,
qstring *errbuf)
{
int skipped = 0;
update_bpt_info_t *b;
update_bpt_info_t *bend = ubpts + nadd;
for ( b=ubpts; b != bend; b++ )
if ( b->code != BPT_OK )
skipped++;
if ( skipped == nadd && ndel == 0 )
{
if ( nbpts != NULL )
*nbpts = 0; // no bpts to update
return DRC_OK;
}
bytevec_t req = prepare_rpc_packet(RPC_UPDATE_BPTS);
req.pack_dd(nadd-skipped);
req.pack_dd(ndel);
ea_t ea = 0;
for ( b=ubpts; b != bend; b++ )
{
if ( b->code == BPT_OK )
{
req.pack_ea64(b->ea-ea); ea = b->ea;
req.pack_dd(b->size);
req.pack_dd(b->type);
req.pack_dd(b->pid);
req.pack_dd(b->tid);
}
}
ea = 0;
bend += ndel;
for ( ; b != bend; b++ )
{
req.pack_ea64(b->ea-ea); ea = b->ea;
req.pack_db(b->orgbytes.size());
req.append(b->orgbytes.begin(), b->orgbytes.size());
req.pack_dd(b->type);
req.pack_dd(b->pid);
req.pack_dd(b->tid);
}
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = unpack_drc(mmdsr);
int ret_nbpts = mmdsr.unpack_dd();
if ( nbpts != NULL )
*nbpts = ret_nbpts;
bend = ubpts + nadd;
for ( b=ubpts; b != bend; b++ )
{
if ( b->code == BPT_OK )
{
b->code = mmdsr.unpack_db();
if ( b->code == BPT_OK && b->type == BPT_SOFT )
{
uchar len = mmdsr.unpack_db();
b->orgbytes.resize(len);
mmdsr.unpack_obj(b->orgbytes.begin(), len);
}
}
}
bend += ndel;
for ( ; b != bend; b++ )
b->code = mmdsr.unpack_db();
if ( errbuf != NULL && drc != DRC_NONE )
*errbuf = mmdsr.unpack_str();
return drc;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_thread_get_sreg_base(ea_t *ea, thid_t tid, int sreg_value, qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_GET_SREG_BASE);
req.pack_dd(tid);
req.pack_dd(sreg_value);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = unpack_drc(mmdsr);
if ( drc == DRC_OK )
*ea = mmdsr.unpack_ea64();
else if ( errbuf != NULL )
*errbuf = mmdsr.unpack_str();
qfree(rp);
return drc;
}
//--------------------------------------------------------------------------
void idaapi rpc_debmod_t::dbg_set_exception_info(const exception_info_t *table, int qty)
{
bytevec_t req = prepare_rpc_packet(RPC_SET_EXCEPTION_INFO);
req.pack_dd(qty);
append_exception_info(req, table, qty);
qfree(send_request_and_receive_reply(req));
}
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::dbg_open_file(const char *file, uint64 *fsize, bool readonly)
{
bytevec_t req = prepare_rpc_packet(RPC_OPEN_FILE);
req.pack_str(file);
req.pack_dd(readonly);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return -1;
memory_deserializer_t mmdsr(rp+1, rp->length);
int fn = mmdsr.unpack_dd();
if ( fn != -1 )
{
if ( fsize != NULL && readonly )
*fsize = mmdsr.unpack_dq();
}
else
{
qerrcode(mmdsr.unpack_dd());
}
qfree(rp);
return fn;
}
//--------------------------------------------------------------------------
void idaapi rpc_debmod_t::dbg_close_file(int fn)
{
bytevec_t req = prepare_rpc_packet(RPC_CLOSE_FILE);
req.pack_dd(fn);
qfree(send_request_and_receive_reply(req));
}
//--------------------------------------------------------------------------
ssize_t idaapi rpc_debmod_t::dbg_read_file(int fn, qoff64_t off, void *buf, size_t size)
{
bytevec_t req = prepare_rpc_packet(RPC_READ_FILE);
req.pack_dd(fn);
req.pack_dq(off);
req.pack_dd((uint32)size);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return -1;
memory_deserializer_t mmdsr(rp+1, rp->length);
int32 rsize = mmdsr.unpack_dd();
if ( size != rsize )
qerrcode(mmdsr.unpack_dd());
if ( rsize > 0 )
{
QASSERT(1204, rsize <= size);
mmdsr.unpack_obj(buf, rsize);
}
qfree(rp);
return rsize;
}
//--------------------------------------------------------------------------
ssize_t idaapi rpc_debmod_t::dbg_write_file(int fn, qoff64_t off, const void *buf, size_t size)
{
bytevec_t req = prepare_rpc_packet(RPC_WRITE_FILE);
req.pack_dd(fn);
req.pack_dq(off);
req.pack_buf(buf, size);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return -1;
memory_deserializer_t mmdsr(rp+1, rp->length);
int32 rsize = mmdsr.unpack_dd();
if ( size != rsize )
qerrcode(mmdsr.unpack_dd());
qfree(rp);
return rsize;
}
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len)
{
bytevec_t req = prepare_rpc_packet(RPC_ISOK_BPT);
req.pack_dd(type);
req.pack_ea64(ea);
req.pack_dd(len+1);
return send_request_get_long_result(req);
}
//--------------------------------------------------------------------------
void idaapi rpc_debmod_t::dbg_set_debugging(bool _debug_debugger)
{
debug_debugger = _debug_debugger;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_init(uint32_t *_flags2, qstring *errbuf)
{
has_pending_event = false;
poll_debug_events = false;
bytevec_t req = prepare_rpc_packet(RPC_INIT);
req.pack_dd(debugger.flags);
req.pack_dd(debug_debugger);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == nullptr )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = unpack_drc(mmdsr);
uint32_t flags2 = mmdsr.unpack_dd();
if ( _flags2 != nullptr )
*_flags2 = flags2;
if ( drc != DRC_OK && errbuf != nullptr )
*errbuf = mmdsr.unpack_str();
qfree(rp);
return drc;
}
//--------------------------------------------------------------------------
void idaapi rpc_debmod_t::dbg_term(void)
{
bytevec_t req = prepare_rpc_packet(RPC_TERM);
qfree(send_request_and_receive_reply(req));
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_get_processes(procinfo_vec_t *procs, qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_GET_PROCESSES);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
procs->qclear();
drc_t drc = unpack_drc(mmdsr);
if ( drc == DRC_OK )
extract_process_info_vec(procs, mmdsr);
else if ( errbuf != NULL )
*errbuf = mmdsr.unpack_str();
qfree(rp);
return drc;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_detach_process(void)
{
return get_drc(RPC_DETACH_PROCESS);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_start_process(
const char *path,
const char *args,
const char *startdir,
int flags,
const char *input_path,
uint32 input_file_crc32,
qstring *errbuf)
{
if ( inf_test_mode() )
flags |= DBG_HIDE_WINDOW;
bytevec_t req = prepare_rpc_packet(RPC_START_PROCESS);
req.pack_str(path);
req.pack_str(args);
req.pack_str(startdir);
req.pack_dd(flags);
req.pack_str(input_path);
req.pack_dd(input_file_crc32);
return process_start_or_attach(req, errbuf);
}
//--------------------------------------------------------------------------
gdecode_t idaapi rpc_debmod_t::dbg_get_debug_event(debug_event_t *event, int timeout_ms)
{
if ( has_pending_event )
{
verbev(("get_debug_event => has pending event, returning it\n"));
*event = pending_event;
has_pending_event = false;
poll_debug_events = false;
return GDE_ONE_EVENT;
}
gdecode_t result = GDE_NO_EVENT;
if ( poll_debug_events )
{
// do we have something waiting?
if ( irs_ready(client_irs, timeout_ms) > 0 )
{
verbev(("get_debug_event => remote has a packet for us\n"));
// get the packet - it can RPC_EVENT or RPC_MSG/RPC_WARNING/RPC_ERROR
bytevec_t empty;
rpc_packet_t *rp = send_request_and_receive_reply(empty, PREQ_GET_EVENT);
verbev(("get_debug_event => processed remote event, has=%d\n", has_pending_event));
if ( rp != NULL )
{
warning("rpc: event protocol error (rp=%p has_event=%d)", rp, has_pending_event);
return GDE_ERROR;
}
}
}
else
{
verbev(("get_debug_event => first time, send GET_DEBUG_EVENT\n"));
bytevec_t req = prepare_rpc_packet(RPC_GET_DEBUG_EVENT);
req.pack_dd(timeout_ms);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return GDE_ERROR;
memory_deserializer_t mmdsr(rp+1, rp->length);
result = gdecode_t(mmdsr.unpack_dd());
if ( result >= GDE_ONE_EVENT )
extract_debug_event(event, mmdsr);
else
poll_debug_events = true;
verbev(("get_debug_event => remote said %d, poll=%d now\n", result, poll_debug_events));
qfree(rp);
}
return result;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_attach_process(pid_t _pid, int event_id, int flags, qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_ATTACH_PROCESS);
req.pack_dd(_pid);
req.pack_dd(event_id);
req.pack_dd(flags);
return process_start_or_attach(req, errbuf);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_prepare_to_pause_process(qstring *errbuf)
{
return get_drc(RPC_PREPARE_TO_PAUSE_PROCESS, errbuf);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_exit_process(qstring *errbuf)
{
return get_drc(RPC_EXIT_PROCESS, errbuf);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_continue_after_event(const debug_event_t *event)
{
bytevec_t req = prepare_rpc_packet(RPC_CONTINUE_AFTER_EVENT);
append_debug_event(req, event);
return send_request_get_drc_result(req, NULL);
}
//--------------------------------------------------------------------------
void idaapi rpc_debmod_t::dbg_stopped_at_debug_event(
import_infos_t *,
bool dlls_added,
thread_name_vec_t *thr_names)
{
bytevec_t req = prepare_rpc_packet(RPC_STOPPED_AT_DEBUG_EVENT);
req.pack_db(dlls_added);
bool ask_thr_names = thr_names != NULL;
req.pack_db(ask_thr_names);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return;
if ( ask_thr_names )
{
memory_deserializer_t mmdsr(rp+1, rp->length);
uint32 n = mmdsr.unpack_dd();
thr_names->resize(n);
for ( uint32 i=0; i < n; ++i )
{
thread_name_t &tn = (*thr_names)[i];
tn.tid = mmdsr.unpack_dd();
tn.name = mmdsr.unpack_str();
}
}
qfree(rp);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_thread_suspend(thid_t tid)
{
return get_drc_int(RPC_TH_SUSPEND, tid);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_thread_continue(thid_t tid)
{
return get_drc_int(RPC_TH_CONTINUE, tid);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_set_resume_mode(thid_t tid, resume_mode_t resmod)
{
bytevec_t req = prepare_rpc_packet(RPC_SET_RESUME_MODE);
req.pack_dd(tid);
req.pack_dd(resmod);
return send_request_get_drc_result(req, NULL);
}
//--------------------------------------------------------------------------
// prepare bitmap of registers belonging to the specified classes
// return size of the bitmap in bits (always the total number of registers)
static int calc_regmap(bytevec_t *regmap, int clsmask)
{
int nregs = debugger.nregs;
regmap->resize((nregs+7)/8, 0);
for ( int i=0; i < nregs; i++ )
if ( (debugger.regs(i).register_class & clsmask) != 0 )
regmap->set_bit(i);
return nregs;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_read_registers(
thid_t tid,
int clsmask,
regval_t *values,
qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_READ_REGS);
req.pack_dd(tid);
req.pack_dd(clsmask);
// append additional information about the class structure
bytevec_t regmap;
int n_regs = calc_regmap(&regmap, clsmask);
req.pack_dd(n_regs);
req.append(regmap.begin(), regmap.size());
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = unpack_drc(mmdsr);
if ( drc == DRC_OK )
unpack_regvals(values, n_regs, regmap.begin(), mmdsr);
else if ( errbuf != NULL )
*errbuf = mmdsr.unpack_str();
qfree(rp);
return drc;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_write_register(
thid_t tid,
int reg_idx,
const regval_t *value,
qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_WRITE_REG);
req.pack_dd(tid);
req.pack_dd(reg_idx);
append_regvals(req, value, 1, NULL);
return send_request_get_drc_result(req, errbuf);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_get_memory_info(meminfo_vec_t &areas, qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_GET_MEMORY_INFO);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = drc_t(mmdsr.unpack_dd() + DRC_IDBSEG);
if ( drc > DRC_NONE )
{
int n = mmdsr.unpack_dd();
areas.resize(n);
for ( int i=0; i < n; i++ )
extract_memory_info(&areas[i], mmdsr);
}
else if ( errbuf != NULL )
{
*errbuf = mmdsr.unpack_str();
}
qfree(rp);
return drc;
}
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::dbg_get_scattered_image(scattered_image_t &si, ea_t base)
{
bytevec_t req = prepare_rpc_packet(RPC_GET_SCATTERED_IMAGE);
req.pack_ea64(base);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return false;
memory_deserializer_t mmdsr(rp+1, rp->length);
int result = mmdsr.unpack_dd() - 2;
if ( result > 0 )
{
int n = mmdsr.unpack_dd();
si.resize(n);
for ( int i=0; i < n; i++ )
extract_scattered_segm(&si[i], mmdsr);
}
qfree(rp);
return result;
}
//--------------------------------------------------------------------------
bool idaapi rpc_debmod_t::dbg_get_image_uuid(bytevec_t *uuid, ea_t base)
{
bytevec_t req = prepare_rpc_packet(RPC_GET_IMAGE_UUID);
req.pack_ea64(base);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return false;
memory_deserializer_t mmdsr(rp+1, rp->length);
bool result = mmdsr.unpack_dd() != 0;
if ( result )
{
int n = mmdsr.unpack_dd();
uuid->append(mmdsr.ptr, n);
}
qfree(rp);
return result;
}
//--------------------------------------------------------------------------
ea_t idaapi rpc_debmod_t::dbg_get_segm_start(ea_t base, const qstring &segname)
{
bytevec_t req = prepare_rpc_packet(RPC_GET_SEGM_START);
req.pack_ea64(base);
req.pack_str(segname.c_str());
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return false;
memory_deserializer_t mmdsr(rp+1, rp->length);
ea_t result = mmdsr.unpack_ea64();
qfree(rp);
return result;
}
//--------------------------------------------------------------------------
ssize_t idaapi rpc_debmod_t::dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_READ_MEMORY);
req.pack_ea64(ea);
req.pack_dd((uint32)size);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return -1;
memory_deserializer_t mmdsr(rp+1, rp->length);
int result = mmdsr.unpack_dd();
if ( result > 0 )
{
QASSERT(1205, result <= size);
mmdsr.unpack_obj(buffer, result);
}
else if ( errbuf != NULL )
{
*errbuf = mmdsr.unpack_str();
}
qfree(rp);
return result;
}
//--------------------------------------------------------------------------
ssize_t idaapi rpc_debmod_t::dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_WRITE_MEMORY);
req.pack_ea64(ea);
req.pack_buf(buffer, size);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return -1;
memory_deserializer_t mmdsr(rp+1, rp->length);
int result = mmdsr.unpack_dd();
if ( errbuf != NULL && result <= 0 )
*errbuf = mmdsr.unpack_str();
qfree(rp);
return result;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_update_call_stack(thid_t tid, call_stack_t *trace)
{
bytevec_t req = prepare_rpc_packet(RPC_UPDATE_CALL_STACK);
req.pack_dd(tid);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = unpack_drc(mmdsr);
if ( drc == DRC_OK )
extract_call_stack(trace, mmdsr);
qfree(rp);
return drc;
}
//--------------------------------------------------------------------------
ea_t idaapi rpc_debmod_t::dbg_appcall(
ea_t func_ea,
thid_t tid,
int stkarg_nbytes,
const struct regobjs_t *regargs,
struct relobj_t *stkargs,
struct regobjs_t *retregs,
qstring *errbuf,
debug_event_t *event,
int flags)
{
bytevec_t req = prepare_rpc_packet(RPC_APPCALL);
req.pack_ea64(func_ea);
req.pack_dd(tid);
req.pack_dd(stkarg_nbytes);
req.pack_dd(flags);
regobjs_t *rr = (flags & APPCALL_MANUAL) == 0 ? retregs : NULL;
append_appcall(req, *regargs, *stkargs, rr);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return BADADDR;
memory_deserializer_t mmdsr(rp+1, rp->length);
ea_t sp = mmdsr.unpack_ea64();
if ( sp == BADADDR )
{
if ( (flags & APPCALL_DEBEV) != 0 )
extract_debug_event(event, mmdsr);
if ( errbuf != NULL )
*errbuf = mmdsr.unpack_str();
}
else if ( (flags & APPCALL_MANUAL) == 0 )
{
if ( retregs != NULL )
extract_regobjs(retregs, true, mmdsr);
}
qfree(rp);
return sp;
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_cleanup_appcall(thid_t tid)
{
bytevec_t req = prepare_rpc_packet(RPC_CLEANUP_APPCALL);
req.pack_dd(tid);
return send_request_get_drc_result(req, NULL);
}
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::dbg_rexec(const char *cmdline)
{
bytevec_t req = prepare_rpc_packet(RPC_REXEC);
req.pack_str(cmdline);
return send_request_get_long_result(req);
}
//--------------------------------------------------------------------------
drc_t idaapi rpc_debmod_t::dbg_bin_search(
ea_t *pea,
ea_t start_ea,
ea_t end_ea,
const compiled_binpat_vec_t &ptns,
int srch_flags,
qstring *errbuf)
{
bytevec_t req = prepare_rpc_packet(RPC_BIN_SEARCH);
req.pack_ea64(start_ea);
req.pack_ea64(end_ea);
// compiled_binpat_vec_t
int sz = ptns.size();
req.pack_dd(sz);
for ( compiled_binpat_vec_t::const_iterator p=ptns.begin();
p != ptns.end();
++p )
{ // compiled_binpat_t
sz = p->bytes.size();
req.pack_buf(p->bytes.begin(), sz);
sz = p->mask.size();
req.pack_buf(p->mask.begin(), sz);
sz = p->strlits.size();
req.pack_dd(sz);
for ( int i=0; i < sz; ++i )
{
req.pack_ea64(p->strlits[i].start_ea);
req.pack_ea64(p->strlits[i].end_ea);
}
req.pack_dd(p->encidx);
}
req.pack_dd(srch_flags);
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = unpack_drc(mmdsr);
if ( drc == DRC_OK )
{
if ( pea != NULL )
*pea = mmdsr.unpack_ea64();
}
else if ( drc != DRC_FAILED ) // DRC_FAILED means not found
{
if ( errbuf != NULL )
*errbuf = mmdsr.unpack_str();
}
qfree(rp);
return drc;
}
//--------------------------------------------------------------------------
drc_t rpc_debmod_t::close_remote()
{
bytevec_t req = prepare_rpc_packet(RPC_OK);
send_data(req);
irs_term(&client_irs);
network_error = false;
return DRC_OK;
}
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::get_system_specific_errno(void) const
{
return irs_get_error(client_irs);
}
//-------------------------------------------------------------------------
drc_t rpc_debmod_t::process_start_or_attach(bytevec_t &req, qstring *errbuf)
{
rpc_packet_t *rp = send_request_and_receive_reply(req);
if ( rp == NULL )
return DRC_NETERR;
memory_deserializer_t mmdsr(rp+1, rp->length);
drc_t drc = unpack_drc(mmdsr);
if ( drc > DRC_NONE )
{
extract_debapp_attrs(&debapp_attrs, mmdsr);
extract_dynamic_register_set(&idaregs, mmdsr);
}
else if ( errbuf != NULL )
{
*errbuf = mmdsr.unpack_str();
}
qfree(rp);
return drc;
}

118
idasdk75/dbg/rpc_debmod.h Normal file
View File

@@ -0,0 +1,118 @@
#ifndef __RPC_DEBUGGER_MODULE__
#define __RPC_DEBUGGER_MODULE__
#include "debmod.h"
#include "dbg_rpc_client.h"
//---------------------------------------------------------------------------
class rpc_debmod_t
: public debmod_t,
public dbg_rpc_client_t
{
drc_t process_start_or_attach(bytevec_t &req, qstring *errbuf);
public:
rpc_debmod_t(const char *default_platform = NULL);
virtual bool idaapi open_remote(const char *hostname, int port_number, const char *password, qstring *errbuf) newapi;
drc_t close_remote();
int send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize)
{
return rpc_engine_t::send_ioctl(fn, buf, size, poutbuf, poutsize);
}
//--------------------------------------------------------------------------
inline int getint(ushort code)
{
bytevec_t req = prepare_rpc_packet((uchar)code);
return send_request_get_long_result(req);
}
drc_t get_drc_int(uchar code, int x)
{
bytevec_t req = prepare_rpc_packet(code);
req.pack_dd(x);
return send_request_get_drc_result(req, NULL);
}
inline drc_t get_drc(ushort code, qstring *errbuf=NULL)
{
bytevec_t req = prepare_rpc_packet((uchar)code);
return send_request_get_drc_result(req, errbuf);
}
//
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
virtual void idaapi dbg_term(void) override;
virtual drc_t idaapi dbg_get_processes(procinfo_vec_t *procs, qstring *errbuf) override;
virtual drc_t idaapi dbg_detach_process(void) override;
virtual drc_t idaapi dbg_start_process(
const char *path,
const char *args,
const char *startdir,
int flags,
const char *input_path,
uint32 input_file_crc32,
qstring *errbuf) override;
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
virtual drc_t idaapi dbg_attach_process(pid_t process_id, int event_id, int flags, qstring *errbuf) override;
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
virtual void idaapi dbg_set_exception_info(const exception_info_t *info, int qty) override;
virtual void idaapi dbg_stopped_at_debug_event(import_infos_t *infos, bool dlls_added, thread_name_vec_t *thr_names) override;
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
virtual drc_t idaapi dbg_read_registers(
thid_t thread_id,
int clsmask,
regval_t *values,
qstring *errbuf) override;
virtual drc_t idaapi dbg_write_register(
thid_t thread_id,
int reg_idx,
const regval_t *value,
qstring *errbuf) override;
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) override;
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &areas, qstring *errbuf) override;
virtual int idaapi dbg_get_scattered_image(scattered_image_t &si, ea_t base) override;
virtual bool idaapi dbg_get_image_uuid(bytevec_t *uuid, ea_t base) override;
virtual ea_t idaapi dbg_get_segm_start(ea_t base, const qstring &segname) override;
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) override;
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
virtual drc_t idaapi dbg_update_bpts(int *nbpts, update_bpt_info_t *bpts, int nadd, int ndel, qstring *errbuf) override;
virtual drc_t idaapi dbg_update_lowcnds(int *nupdated, const lowcnd_t *lowcnds, int nlowcnds, qstring *errbuf) override;
virtual drc_t idaapi dbg_eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf) override;
virtual int idaapi dbg_open_file(const char *file, uint64 *fsize, bool readonly) override;
virtual void idaapi dbg_close_file(int fn) override;
virtual ssize_t idaapi dbg_read_file(int fn, qoff64_t off, void *buf, size_t size) override;
virtual ssize_t idaapi dbg_write_file(int fn, qoff64_t off, const void *buf, size_t size) override;
virtual int idaapi handle_ioctl(int fn, const void *buf, size_t size, void **outbuf, ssize_t *outsize) override;
virtual int idaapi get_system_specific_errno(void) const override;
virtual drc_t idaapi dbg_update_call_stack(thid_t, call_stack_t *) override;
virtual ea_t idaapi dbg_appcall(
ea_t func_ea,
thid_t tid,
int stkarg_nbytes,
const struct regobjs_t *regargs,
struct relobj_t *stkargs,
struct regobjs_t *retregs,
qstring *errbuf,
debug_event_t *event,
int flags) override;
virtual drc_t idaapi dbg_cleanup_appcall(thid_t tid) override;
virtual int get_regidx(const char *, int *) override { INTERR(30116); }
virtual int idaapi dbg_rexec(const char *cmdline) override;
virtual drc_t idaapi dbg_bin_search(
ea_t *ea,
ea_t start_ea,
ea_t end_ea,
const compiled_binpat_vec_t &ptns,
int srch_flags,
qstring *errbuf) override;
};
#endif

224
idasdk75/dbg/server.cpp Normal file
View File

@@ -0,0 +1,224 @@
/*
IDA remote debugger server
*/
#ifdef _WIN32
// We use the deprecated inet_ntoa() function for Windows XP compatibility.
//lint -e750 local macro '' not referenced
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
#include <expr.hpp>
#include "server.h"
// Provide dummy versions for tinfo copy/clear. Debugger servers do not use them
#if !defined(__NT__)
void ida_export copy_tinfo_t(tinfo_t *, const tinfo_t &) {}
void ida_export clear_tinfo_t(tinfo_t *) {}
#endif
// We don't have a kernel. Provide envvar-based debug file directory retrieval.
#if defined(__LINUX__)
static bool _elf_debug_file_directory_resolved = false;
static qstring _elf_debug_file_directory;
idaman const char *ida_export get_elf_debug_file_directory()
{
if ( !_elf_debug_file_directory_resolved )
{
if ( !qgetenv("DEBUG_FILE_DIRECTORY", &_elf_debug_file_directory) )
qgetenv("ELF_DEBUG_FILE_DIRECTORY", &_elf_debug_file_directory);
if ( _elf_debug_file_directory.empty() )
_elf_debug_file_directory = "/usr/lib/debug";
_elf_debug_file_directory_resolved = true;
}
return _elf_debug_file_directory.c_str();
}
//-------------------------------------------------------------------------
#ifdef TESTABLE_BUILD
static std::map<int,qstring> _pid_elf_debug_file_directories;
void set_elf_debug_file_directory_for_pid(int pid, const char *path)
{
_pid_elf_debug_file_directories[pid] = path;
}
//-------------------------------------------------------------------------
const char *get_elf_debug_file_directory_for_pid(int pid)
{
const char *found = NULL;
std::map<int,qstring>::const_iterator it = _pid_elf_debug_file_directories.find(pid);
if ( it != _pid_elf_debug_file_directories.end() )
found = it->second.begin();
else
found = get_elf_debug_file_directory();
return found;
}
#endif
#endif
//lint -esym(714, dump_udt) not referenced
void dump_udt(const char *, const struct udt_type_data_t &) {}
//--------------------------------------------------------------------------
// SERVER GLOBAL VARIABLES
#ifdef __SINGLE_THREADED_SERVER__
dbgsrv_dispatcher_t dispatcher(false);
static bool init_lock(void) { return true; }
bool lock_begin(void) { return true; }
bool lock_end(void) { return true; }
#else
dbgsrv_dispatcher_t dispatcher(true);
static qmutex_t g_mutex = NULL;
static bool init_lock(void) { g_mutex = qmutex_create(); return g_mutex != NULL; }
bool lock_begin(void) { return qmutex_lock(g_mutex); }
bool lock_end(void) { return qmutex_unlock(g_mutex); }
#endif
//--------------------------------------------------------------------------
dbg_rpc_handler_t *g_global_server = NULL;
//--------------------------------------------------------------------------
// perform an action (func) on all debuggers
int for_all_debuggers(debmod_visitor_t &v)
{
int code = 0;
dispatcher.clients_list->lock();
{
client_handlers_list_t::storage_t::iterator it;
for ( it = dispatcher.clients_list->storage.begin();
it != dispatcher.clients_list->storage.end();
++it )
{
dbg_rpc_handler_t *h = (dbg_rpc_handler_t *) it->first;
code = v.visit(h->get_debugger_instance());
if ( code != 0 )
break;
}
}
dispatcher.clients_list->unlock();
return code;
}
//-------------------------------------------------------------------------
dbgsrv_dispatcher_t::dbgsrv_dispatcher_t(bool multi_threaded)
: base_dispatcher_t(multi_threaded),
broken_conns_supported(false),
on_broken_conn(BCH_DEFAULT)
{
port_number = DEBUGGER_PORT_NUMBER;
}
//-------------------------------------------------------------------------
void dbgsrv_dispatcher_t::collect_cliopts(cliopts_t *out)
{
struct ida_local ns_t
{
static void _set_dpassword(const char *value, void *ud)
{
((dbgsrv_dispatcher_t *) ud)->server_password = value;
}
static void _set_broken_connections_keep_debmod(const char *, void *ud)
{
((dbgsrv_dispatcher_t *) ud)->on_broken_conn = BCH_KEEP_DEBMOD;
}
static void _set_closing_session_kill_debuggee(const char *, void *ud)
{
((dbgsrv_dispatcher_t *) ud)->on_broken_conn = BCH_KILL_PROCESS;
}
};
static const cliopt_t cliopts[] =
{
{ 'P', "password", "Password", ns_t::_set_dpassword, 1 },
};
// the following options are valid only if broken connections are supported
static const cliopt_t bc_cliopts[] =
{
{
'k',
"on-broken-connection-keep-session",
"Keep debugger session alive when connection breaks",
ns_t::_set_broken_connections_keep_debmod,
0,
},
{
'K',
"on-stop-kill-process",
"Kill debuggee when closing session",
ns_t::_set_closing_session_kill_debuggee,
0,
},
};
base_dispatcher_t::collect_cliopts(out);
for ( size_t i = 0; i < qnumber(cliopts); ++i )
out->push_back(cliopts[i]);
if ( broken_conns_supported )
for ( size_t i = 0; i < qnumber(bc_cliopts); ++i )
out->push_back(bc_cliopts[i]);
}
//-------------------------------------------------------------------------
client_handler_t *dbgsrv_dispatcher_t::new_client_handler(idarpc_stream_t *_irs)
{
dbg_rpc_handler_t *h = new dbg_rpc_handler_t(_irs, this);
h->verbose = verbose;
void *params = NULL;
#if defined(__LINUX__) && defined(TESTABLE_BUILD)
params = (void *) get_elf_debug_file_directory_for_pid; //lint !e611 cast between pointer to function type '' and pointer to object type 'void *'
#endif
h->set_debugger_instance(create_debug_session(params));
g_global_server = h;
return h;
}
//-------------------------------------------------------------------------
void dbgsrv_dispatcher_t::shutdown_gracefully(int signum)
{
base_dispatcher_t::shutdown_gracefully(signum);
term_subsystem();
}
//--------------------------------------------------------------------------
// debugger remote server - TCP/IP mode
int NT_CDECL main(int argc, const char *argv[])
{
#ifdef ENABLE_LOWCNDS
init_idc();
#endif
// call the debugger module to initialize its subsystem once
if ( !init_lock() || !init_subsystem() )
{
lprintf("Could not initialize subsystem!");
return -1;
}
qstring password;
if ( qgetenv("IDA_DBGSRV_PASSWD", &password) )
dispatcher.server_password = password;
int ida_major = IDA_SDK_VERSION / 100;
#if (IDA_SDK_VERSION % 10) == 0
int ida_minor = (IDA_SDK_VERSION % 100)/10; //740 -> 4
#else
int ida_minor = IDA_SDK_VERSION % 100; //741 -> 41
#endif
lprintf("IDA " SYSTEM SYSBITS " remote debug server(" __SERVER_TYPE__ ") "
"v%d.%d.%d. Hex-Rays (c) 2004-2020\n",
ida_major, ida_minor, IDD_INTERFACE_VERSION);
dispatcher.broken_conns_supported = debmod_t::reuse_broken_connections;
cliopts_t cliopts(lprintf);
dispatcher.collect_cliopts(&cliopts);
cliopts.apply(argc, argv, &dispatcher);
dispatcher.install_signal_handlers();
dispatcher.dispatch();
}

58
idasdk75/dbg/server.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef SERVER_H
#define SERVER_H
#include <network.hpp>
#ifdef __NT__
//# ifndef SIGHUP
//# define SIGHUP 1
//# endif
# define DEBUGGER_ID DEBUGGER_ID_X86_IA32_WIN32_USER
#else // not NT, i.e. UNIX
# if defined(__LINUX__)
# if defined(__ARM__)
# define DEBUGGER_ID DEBUGGER_ID_ARM_LINUX_USER
# else
# define DEBUGGER_ID DEBUGGER_ID_X86_IA32_LINUX_USER
# endif
# elif defined(__MAC__)
# define DEBUGGER_ID DEBUGGER_ID_X86_IA32_MACOSX_USER
# endif
# include <sys/socket.h>
# include <netinet/in.h>
#endif // !__NT__
enum broken_conn_hndl_t
{
BCH_DEFAULT,
BCH_KEEP_DEBMOD,
BCH_KILL_PROCESS,
};
struct dbgsrv_dispatcher_t : public base_dispatcher_t
{
qstring server_password;
bool broken_conns_supported;
broken_conn_hndl_t on_broken_conn;
dbgsrv_dispatcher_t(bool multi_threaded);
virtual void collect_cliopts(cliopts_t *out) override;
virtual client_handler_t *new_client_handler(idarpc_stream_t *irs) override;
virtual void shutdown_gracefully(int signum) override;
};
#include "debmod.h"
#include "dbg_rpc_hlp.h"
#include "dbg_rpc_handler.h"
// // sizeof(ea_t)==8 and sizeof(size_t)==4 servers cannot be used to debug 64-bit
// // applications. but to debug 32-bit applications, simple 32-bit servers
// // are enough and can work with both 32-bit and 64-bit versions of ida.
// // so, there is no need to build sizeof(ea_t)==8 and sizeof(size_t)==4 servers
// #if defined(__EA64__) == defined(__X86__)
// #error "Mixed mode servers do not make sense, they should not be compiled"
// #endif
#endif

17
idasdk75/dbg/server.mak Normal file
View File

@@ -0,0 +1,17 @@
SERVER_LIBS += $(L)dbg_server$(A)
SERVER_LIBS += $(L)dbg_rpc$(A)
SERVER_LIBS += $(L)dbg_proc$(A)
SERVER_LIBS += $(L)network$(A)
SERVER_LIBS += $(DUMB)
SERVER_LIBS += $(L)unicode$(A)
SERVER_LIBS += $(L)pro$(A)
SERVER_LIBS += $(L)compress$(A)
server: $(SERVERS)
$(SERVERS): LDFLAGS += $(SERVER_LDFLAGS)
$(SERVERS): STDLIBS += $(SERVER_STDLIBS)
$(SERVERS): $(SERVER_OBJS) $(SERVER_LIBS)
$(call link_exe, $(SERVER_OBJS), $(SERVER_LIBS))
$(CHECKSYMS_CMD)
$(SERVER_POSTACTION)

174
idasdk75/dbg/win32/makefile Normal file
View File

@@ -0,0 +1,174 @@
include ../../allmake.mak
GOALS-$(BUILD_IDA) += modules # target in $(IDA)module.mak
GOALS-$(BUILD_DBGSRV) += server # target in $(IDA)dbg/server.mak
.PHONY: $(GOALS-1)
all: $(GOALS-1)
#----------------------------------------------------------------------
ifdef __NT__
ifndef __X86__
SERVER = win64_remote$(B)
else
SERVER = win32_remote$(B)
endif
endif
ifdef SERVER
SERVERS += $(call server_exe,$(SERVER))
endif
#----------------------------------------------------------------------
STUB = $(call module_dll,win32_stub)
ifdef BUILD_IDA
MODULES += $(STUB)
endif
#----------------------------------------------------------------------
USER = $(call module_dll,win32_user)
ifeq ($(and $(BUILD_IDA),$(__NT__)),1)
MODULES += $(USER)
endif
#----------------------------------------------------------------------
# we explicitly added our module targets
NO_DEFAULT_TARGETS = 1
# NOTE: all MODULES must be defined before including plugin.mak.
include ../plugin.mak
# NOTE: target-specific rules and dependencies that use variable
# expansion to name the target (such as "$(MODULE): [...]") must
# come after including plugin.mak
#----------------------------------------------------------------------
# select OBJS common to user plugin and debugger server
BASE_OBJS-$(__NT__) += $(F)win32_debmod$(O)
BASE_OBJS-$(__NT__) += $(F)win32_util$(O)
BASE_OBJS-$(__NT__) += $(F)winbase_debmod$(O)
BASE_OBJS += $(BASE_OBJS-1)
#----------------------------------------------------------------------
SERVER_OBJS += $(F)win32_server$(O)
SERVER_OBJS += $(F)tilfuncs$(O)
SERVER_OBJS += $(BASE_OBJS)
SERVER_STDLIBS += ole32.lib
SERVER_STDLIBS += oleaut32.lib
include ../server.mak
#----------------------------------------------------------------------
STUB_OBJS += $(F)win32_stub$(O)
STUB_OBJS += $(F)w32sehch$(O)
$(STUB): MODULE_OBJS += $(STUB_OBJS)
$(STUB): $(STUB_OBJS)
#----------------------------------------------------------------------
USER_OBJS += $(F)win32_user$(O)
USER_OBJS += $(F)w32sehch$(O)
USER_OBJS += $(BASE_OBJS)
$(USER): MODULE_OBJS += $(USER_OBJS)
$(USER): $(USER_OBJS)
$(USER): STDLIBS += user32.lib
#----------------------------------------------------------------------
include $(IDA)objdir.mak
# MAKEDEP dependency list ------------------
$(F)tilfuncs$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)diskio.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
$(I)ins/pc.hpp $(I)intel.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)name.hpp \
$(I)netnode.hpp $(I)network.hpp $(I)pro.h $(I)range.hpp \
$(I)segment.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../../ldr/pe/cor.h ../../ldr/pe/corerror.h \
../../ldr/pe/corhdr.h ../../ldr/pe/mycor.h \
../../ldr/pe/pe.h ../../plugins/pdb/common.cpp \
../../plugins/pdb/cvconst.h ../../plugins/pdb/dbghelp.h \
../../plugins/pdb/dia2.h ../../plugins/pdb/idaaccess.hpp \
../../plugins/pdb/msdia.cpp ../../plugins/pdb/msdia.hpp \
../../plugins/pdb/pdb.hpp \
../../plugins/pdb/pdbaccess.hpp \
../../plugins/pdb/pdbida.hpp \
../../plugins/pdb/pdblocal.cpp \
../../plugins/pdb/pdblocal.hpp \
../../plugins/pdb/varser.hpp ../debmod.h tilfuncs.cpp \
tilfuncs.hpp
$(F)w32sehch$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)dbg.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
$(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp \
$(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp $(I)name.hpp \
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)ua.hpp $(I)xref.hpp w32sehch.cpp w32sehch.h
$(F)win32_debmod$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)dbg.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)err.h $(I)exehdr.h $(I)fixup.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \
$(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)offset.hpp $(I)pro.h $(I)prodir.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../../ldr/pe/../idaldr.h \
../../ldr/pe/common.cpp ../../ldr/pe/common.h \
../../ldr/pe/pe.h ../dbg_pe_hlp.cpp ../deb_pc.hpp \
../debmod.h ../pc_debmod.h ../pc_regs.hpp \
win32_debmod.cpp win32_debmod.h win32_debmod_impl.cpp \
win32_rpc.h win32_undoc.h win32_util.hpp \
winbase_debmod.h
$(F)win32_server$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \
$(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../../ldr/pe/cor.h ../../ldr/pe/corerror.h \
../../ldr/pe/corhdr.h ../../ldr/pe/mycor.h \
../../ldr/pe/pe.h ../../plugins/pdb/cvconst.h \
../../plugins/pdb/dia2.h ../../plugins/pdb/idaaccess.hpp \
../../plugins/pdb/msdia.hpp ../../plugins/pdb/pdb.hpp \
../../plugins/pdb/pdbaccess.hpp \
../../plugins/pdb/pdbida.hpp \
../../plugins/pdb/pdblocal.hpp ../dbg_rpc_hlp.h \
../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \
tilfuncs.hpp win32_debmod.h win32_rpc.h win32_server.cpp \
win32_util.hpp winbase_debmod.h
$(F)win32_stub$(O): $(I)../ldr/pe/pe.h $(I)../plugins/pdb/pdb.hpp \
$(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../../ldr/pe/pe.h ../common_local_impl.cpp \
../common_stub_impl.cpp ../dbg_rpc_client.h \
../dbg_rpc_engine.h ../dbg_rpc_hlp.h ../deb_pc.hpp \
../debmod.h ../pc_local_impl.cpp ../pc_regs.hpp \
../rpc_debmod.h w32sehch.h win32_local_impl.cpp \
win32_rpc.h win32_stub.cpp
$(F)win32_user$(O): $(I)../ldr/pe/pe.h $(I)../plugins/pdb/pdb.hpp \
$(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../../ldr/pe/pe.h ../common_local_impl.cpp \
../common_stub_impl.cpp ../dbg_rpc_hlp.h ../deb_pc.hpp \
../debmod.h ../pc_debmod.h ../pc_local_impl.cpp \
../pc_regs.hpp w32sehch.h win32_debmod.h \
win32_local_impl.cpp win32_rpc.h win32_server_stub.cpp \
win32_user.cpp win32_util.hpp winbase_debmod.h
$(F)win32_util$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)ua.hpp $(I)xref.hpp ../deb_pc.hpp ../debmod.h \
../pc_debmod.h ../pc_regs.hpp win32_util.cpp \
win32_util.hpp winbase_debmod.h
$(F)winbase_debmod$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp \
$(I)netnode.hpp $(I)network.hpp $(I)pro.h $(I)range.hpp \
$(I)segment.hpp $(I)ua.hpp $(I)xref.hpp ../deb_pc.hpp \
../debmod.h ../pc_debmod.h ../pc_regs.hpp win32_util.hpp \
winbase_debmod.cpp winbase_debmod.h

View File

@@ -0,0 +1,256 @@
#include <set>
#include <pro.h>
#include <name.hpp>
#include <kernwin.hpp>
#include <dbg.hpp>
#include <loader.hpp>
#include "w32sehch.h"
static int req_id = -1;
//-------------------------------------------------------------------------
// non-modal exception handler chooser
struct x86seh_chooser_t : public chooser_t
{
protected:
thid_t tid;
qvector<uint32> list; //lint !e958 padding is required to align members
qstring title_;
static const int widths_[];
static const char *const header_[];
enum { ICON = 144 };
public:
// this object must be allocated using `new`
x86seh_chooser_t(thid_t tid);
virtual ~x86seh_chooser_t()
{
unhook_from_notification_point(
HT_DBG,
dbg_handler, const_cast<char *>(title));
}
ssize_t choose(uint32 addr = uint32(-1)) //lint !e1511 member hides non-virtual member
{
return ::choose(this, &addr);
}
virtual const void *get_obj_id(size_t *len) const override
{
*len = sizeof(tid);
return &tid;
}
virtual size_t idaapi get_count() const override { return list.size(); }
virtual void idaapi get_row(
qstrvec_t *cols,
int *icon_,
chooser_item_attrs_t *attrs,
size_t n) const override;
virtual cbret_t idaapi enter(size_t n) override;
// calculate the location of the item,
// `item_data` is a pointer to a 32-bit address
virtual ssize_t idaapi get_item_index(const void *item_data) const override;
virtual bool idaapi init() override;
virtual cbret_t idaapi refresh(ssize_t n) override;
protected:
static ssize_t idaapi dbg_handler(void *ud, int notif_code, va_list va);
};
//-------------------------------------------------------------------------
const int x86seh_chooser_t::widths_[] =
{
CHCOL_HEX | 10, // Address
30, // Name
};
const char *const x86seh_chooser_t::header_[] =
{
"Address", // 0
"Name", // 1
};
//-------------------------------------------------------------------------
inline x86seh_chooser_t::x86seh_chooser_t(thid_t tid_)
: chooser_t(CH_NOBTNS | CH_FORCE_DEFAULT | CH_CAN_REFRESH,
qnumber(widths_), widths_, header_),
tid(tid_),
list()
{
title_.sprnt("[%04X] - Structured exception handlers list", tid);
title = title_.c_str();
CASSERT(qnumber(widths_) == qnumber(header_));
icon = ICON;
hook_to_notification_point(
HT_DBG,
dbg_handler, const_cast<char *>(title));
}
//-------------------------------------------------------------------------
void idaapi x86seh_chooser_t::get_row(
qstrvec_t *cols_,
int *,
chooser_item_attrs_t *,
size_t n) const
{
// assert: n < list.size()
uint32 addr = list[n];
qstrvec_t &cols = *cols_;
cols[0].sprnt("%08X", addr);
get_nice_colored_name(&cols[1], addr, GNCN_NOCOLOR | GNCN_NOLABEL);
CASSERT(qnumber(header_) == 2);
}
//-------------------------------------------------------------------------
chooser_t::cbret_t idaapi x86seh_chooser_t::enter(size_t n)
{
// assert: n < list.size()
ea_t ea = ea_t(list[n]);
if ( !is_code(get_flags(ea)) )
create_insn(ea);
jumpto(ea);
return cbret_t(); // nothing changed
}
//------------------------------------------------------------------------
ssize_t idaapi x86seh_chooser_t::get_item_index(const void *item_data) const
{
if ( list.empty() )
return NO_SELECTION;
// `item_data` is a pointer to a 32-bit address
uint32 item_addr = *(const uint32 *)item_data;
if ( item_addr == uint32(-1) )
return 0; // first item by default
// find `item_script` in the list
const uint32 *p = list.find(item_addr);
if ( p != list.end() )
return p - list.begin();
return 0; // first item by default
}
//--------------------------------------------------------------------------
bool idaapi x86seh_chooser_t::init()
{
// rebuild the handlers list
uint64 fs_sel;
ea_t fs_base;
uint32 excr_ea;
list.clear();
if ( !get_reg_val("fs", &fs_sel)
|| internal_get_sreg_base(&fs_base, tid, int(fs_sel)) <= DRC_NONE
|| read_dbg_memory(fs_base, &excr_ea, sizeof(excr_ea)) != sizeof(excr_ea) )
{
warning("Failed to build the SEH list for thread %08X", tid);
return false; // do not show the empty chooser
}
struct EXC_REG_RECORD
{
uint32 p_prev;
uint32 p_handler;
};
EXC_REG_RECORD rec;
std::set<uint32> seen;
while ( excr_ea != 0xffffffff )
{
if ( read_dbg_memory(excr_ea, &rec, sizeof(rec)) != sizeof(rec) )
break;
if ( !seen.insert(excr_ea).second )
{
msg("Circular SEH record has been detected\n");
break;
}
list.push_back(rec.p_handler);
excr_ea = rec.p_prev;
}
return true;
}
//------------------------------------------------------------------------
chooser_t::cbret_t idaapi x86seh_chooser_t::refresh(ssize_t n)
{
uint32 item_addr = uint32(-1);
if ( n >= 0 && n < list.size() )
item_addr = list[n]; // remember the currently selected handler
init();
if ( n < 0 )
return NO_SELECTION;
ssize_t idx = get_item_index(&item_addr);
// no need to adjust `idx` as get_item_index() returns first item by
// default
return idx;
}
//-------------------------------------------------------------------------
ssize_t idaapi x86seh_chooser_t::dbg_handler(void *ud, int code, va_list)
{
if ( code == dbg_suspend_process )
{
const char *ttl = static_cast<const char *>(ud);
refresh_chooser(ttl);
}
return 0;
}
//-------------------------------------------------------------------------
struct show_window_ah_t : public action_handler_t
{
virtual int idaapi activate(action_activation_ctx_t *) override
{
thid_t tid = get_current_thread();
x86seh_chooser_t *ch = new x86seh_chooser_t(tid);
return ch->choose() == 0;
} //lint !e429 Custodial pointer 'ch' has not been freed or returned
virtual action_state_t idaapi update(action_update_ctx_t *) override
{
return AST_ENABLE;
}
};
static show_window_ah_t show_window_ah;
//---------------------------------------------------------------------------
void remove_x86seh_menu()
{
if ( req_id != -1 )
{
cancel_exec_request(req_id);
req_id = -1;
}
}
//---------------------------------------------------------------------------
void install_x86seh_menu()
{
// HACK: We queue this request because commdbg apparently enables the debug menus
// just after calling init_debugger().
struct uireq_install_menu_t: public ui_request_t
{
virtual bool idaapi run() override
{
if ( !inf_is_64bit() )
{
register_and_attach_to_menu(
"Debugger/Debugger windows/Stack trace",
"dbg:sehList", "SEH list", NULL, SETMENU_APP,
&show_window_ah,
&PLUGIN,
ADF_OT_PLUGIN);
}
req_id = -1;
return false;
}
};
req_id = execute_ui_requests(new uireq_install_menu_t, NULL);
}

View File

@@ -0,0 +1,7 @@
#ifndef __W32SEHCH__
#define __W32SEHCH__
void install_x86seh_menu();
void remove_x86seh_menu();
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,428 @@
#ifndef __WIN32_DEBUGGER_MODULE__
#define __WIN32_DEBUGGER_MODULE__
#include <windows.h>
#include <Tlhelp32.h>
#include "../../ldr/pe/pe.h"
#include "winbase_debmod.h"
//-V::720 It is advised to utilize the 'SuspendThread' function only when developing a debugger
// Type definitions
class win32_debmod_t;
//--------------------------------------------------------------------------
// image information
struct image_info_t
{
image_info_t() { memset(this, 0, sizeof(*this)); }
image_info_t(win32_debmod_t *);
image_info_t(win32_debmod_t *, ea_t _base, uint32 _imagesize, const qstring &_name);
image_info_t(win32_debmod_t *, const LOAD_DLL_DEBUG_INFO &i, uint32 _imagesize, const char *_name);
image_info_t(win32_debmod_t *, const modinfo_t &m);
win32_debmod_t *sess;
ea_t base;
uval_t imagesize;
qstring name;
LOAD_DLL_DEBUG_INFO dll_info;
};
// key: image base address
typedef std::map<ea_t, image_info_t> images_t;
//-------------------------------------------------------------------------
struct context_holder_t
{
bytevec_t buffer;
PCONTEXT ptr;
context_holder_t() : ptr(NULL) {}
};
//-------------------------------------------------------------------------
struct context_helper_t
{
typedef DWORD64 (WINAPI *PGETENABLEDXSTATEFEATURES)();
PGETENABLEDXSTATEFEATURES pfnGetEnabledXStateFeatures;
typedef BOOL (WINAPI *PINITIALIZECONTEXT)(PVOID Buffer, DWORD ContextFlags, PCONTEXT *Context, PDWORD ContextLength);
PINITIALIZECONTEXT pfnInitializeContext;
typedef BOOL (WINAPI *PGETXSTATEFEATURESMASK)(PCONTEXT Context, PDWORD64 FeatureMask);
PGETXSTATEFEATURESMASK pfnGetXStateFeaturesMask;
typedef PVOID (WINAPI *LOCATEXSTATEFEATURE)(PCONTEXT Context, DWORD FeatureId, PDWORD Length);
LOCATEXSTATEFEATURE pfnLocateXStateFeature;
typedef BOOL (WINAPI *SETXSTATEFEATURESMASK)(PCONTEXT Context, DWORD64 FeatureMask);
SETXSTATEFEATURESMASK pfnSetXStateFeaturesMask;
typedef BOOL (WINAPI *COPYCONTEXT)(PCONTEXT Destination, DWORD ContextFlags, PCONTEXT Source);
COPYCONTEXT pfnCopyContext;
int xstate_context_size;
bool get_xstate_context_size(int *out_ctxsz);
context_helper_t() { clear(); }
bool create_context(context_holder_t *out, int *ctxflags);
bool xstate_helpers_loaded() const { return xstate_context_size > 0; }
void clear();
};
//--------------------------------------------------------------------------
// thread information
struct thread_info_t : public CREATE_THREAD_DEBUG_INFO
{
thread_info_t(
win32_debmod_t *dm,
const CREATE_THREAD_DEBUG_INFO &i,
thid_t t,
wow64_state_t wow64_state);
win32_debmod_t *debmod;
thid_t tid; // thread id
int suspend_count;
ea_t bpt_ea;
int flags;
#define THR_CLSMASK 0x0007 // valid register classes in CONTEXT structure
// we use X86_RC.. constants here
#define THR_TRACING 0x0100 // expecting a STEP event
#define THR_FSSAVED 0x0200 // remembered FS value
#define THR_WOW64 0x0400 // is wow64 process?
#define THR_NEWNAME 0x0800 // thread was renamed
context_holder_t ctx_holder;
ea_t callgate_ea;
qstring name;
void invalidate_context(void) { flags &= ~THR_CLSMASK; if ( ctx_holder.ptr != NULL ) get_ctx().ContextFlags = 0; }
bool read_context(int clsmask);
bool write_context(int clsmask);
void cvt_from_wow64(
const WOW64_CONTEXT &wow64ctx,
int clsmask,
PCONTEXT xstate_ctx) const;
void cvt_to_wow64(
WOW64_CONTEXT *wow64ctx,
PCONTEXT xstate_ctx,
int clsmask) const;
bool toggle_tbit(bool set_tbit);
bool is_tracing(void) const { return (flags & THR_TRACING) != 0; }
void set_tracing(void) { flags |= THR_TRACING; }
void clr_tracing(void) { flags &= ~THR_TRACING; }
#ifdef __X86__
ea_t get_ip(void) { return read_context(X86_RC_GENERAL) ? get_ctx().Eip : BADADDR; }
#else
ea_t get_ip(void) { return read_context(X86_RC_GENERAL) ? get_ctx().Rip : BADADDR; }
#endif
bool is_new_name(void) const { return (flags & THR_NEWNAME) != 0; }
void clr_new_name(void) { flags &= ~THR_NEWNAME; }
void set_new_name(void) { flags |= THR_NEWNAME; }
CONTEXT &get_ctx() const { QASSERT(1669, ctx_holder.ptr != NULL); return *ctx_holder.ptr; }
};
//--------------------------------------------------------------------------
inline thread_info_t::thread_info_t(
win32_debmod_t *dm,
const CREATE_THREAD_DEBUG_INFO &i,
thid_t t,
wow64_state_t wow64_state)
: CREATE_THREAD_DEBUG_INFO(i), tid(t), suspend_count(0), bpt_ea(BADADDR),
debmod(dm),
flags(wow64_state > 0 ? THR_WOW64 : 0),
callgate_ea(0)
{
}
//--------------------------------------------------------------------------
// Check if the context structure has valid values at the specified portion
// portion is a conbination of CONTEXT_... bitmasks
inline bool has_portion(const CONTEXT &ctx, int portion)
{
return (ctx.ContextFlags & portion & 0xFFFF) != 0;
}
//--------------------------------------------------------------------------
// (tid -> info)
struct threads_t: public std::map<DWORD, thread_info_t>
{
thread_info_t *get(DWORD tid)
{
const iterator it = find(tid);
if ( it == end() )
return NULL;
return &it->second;
}
};
//--------------------------------------------------------------------------
typedef qvector<thread_info_t> threadvec_t;
//--------------------------------------------------------------------------
// structure for the internal breakpoint information for threads
struct internal_bpt_info_t
{
int count; // number of times this breakpoint is 'set'
uchar orig_bytes[BPT_CODE_SIZE]; // original byte values
};
typedef std::map<ea_t, internal_bpt_info_t> bpt_info_t;
//--------------------------------------------------------------------------
typedef int (*process_cb_t)(debmod_t *, PROCESSENTRY32 *pe32, void *ud);
typedef int (*module_cb_t)(debmod_t *, MODULEENTRY32 *me32, void *ud);
//----------------------------------------------------------------------------
// A live PDB session, that will be used remotely (typically by non-windows machines).
struct pdb_remote_session_t;
void close_pdb_remote_session(pdb_remote_session_t *);
//Wow64-specific events
#ifndef STATUS_WX86_BREAKPOINT
# define STATUS_WX86_BREAKPOINT 0x4000001f
#endif
#ifndef STATUS_WX86_SINGLE_STEP
# define STATUS_WX86_SINGLE_STEP 0x4000001e
#endif
//--------------------------------------------------------------------------
class win32_debmod_t : public winbase_debmod_t
{
typedef winbase_debmod_t inherited;
gdecode_t get_debug_event(debug_event_t *event, int timeout_ms);
void check_thread(bool must_be_main_thread) const;
void add_thread(const CREATE_THREAD_DEBUG_INFO &thr_info, thid_t tid);
void install_callgate_workaround(thread_info_t *ti, const debug_event_t *event);
int describe_stack_segment(
thid_t tid,
images_t &thr_ranges,
images_t &cls_ranges,
const _NT_TIB &tib,
const char *pref);
void update_thread_names(thread_name_vec_t *thr_names);
bool get_pe_exports_from_path(
const char *path,
linput_t *li,
ea_t imagebase,
name_info_t &ni,
const char *exported_name=NULL) const;
void patch_context_struct(
CONTEXT &ctx,
int reg_idx,
const thread_info_t *ti,
const regval_t *value) const;
public:
// debugged process information
qstring process_path;
HANDLE thread_handle;
HANDLE redirin_handle;
HANDLE redirout_handle;
attach_status_t attach_status;
HANDLE attach_evid;
int8 expecting_debug_break;
bool stop_at_ntdll_bpts;
images_t curproc; // image of the running process
images_t dlls; // list of loaded DLLs
images_t images; // list of detected PE images
images_t thread_ranges; // list of ranges related to threads
images_t class_ranges; // list of ranges related to class names
easet_t dlls_to_import; // list of dlls to import information from
modinfo_t binary_to_import; // executable to import information from
bpt_info_t thread_bpts;
threads_t threads;
// ID of a thread for which we must emulate a STEP event on XP (using a breakpoint)
thid_t winxp_step_thread;
CREATE_PROCESS_DEBUG_INFO cpdi;
debug_event_t *in_event; // current debug event
bool fake_suspend_event;
bool exiting;
bool pause_requested;
procinfo_vec_t processes;
// threads suspended by the fiber created for restoring broken connections
threadvec_t _suspended_threads;
// event to wait until the broken connection is completely restored
HANDLE broken_event_handle;
context_helper_t context_helper;
// Module specific methods, to be implemented
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
virtual void idaapi dbg_term(void) override;
virtual drc_t idaapi dbg_detach_process(void) override;
virtual drc_t idaapi dbg_start_process(
const char *path,
const char *args,
const char *startdir,
int flags,
const char *input_path,
uint32 input_file_crc32,
qstring *errbuf) override;
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
virtual drc_t idaapi dbg_attach_process(
pid_t process_id,
int event_id,
int flags,
qstring *errbuf) override;
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
virtual void idaapi dbg_stopped_at_debug_event(
import_infos_t *infos,
bool dlls_added,
thread_name_vec_t *thr_names) override;
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
virtual drc_t idaapi dbg_read_registers(
thid_t thread_id,
int clsmask,
regval_t *values,
qstring *errbuf) override;
virtual drc_t idaapi dbg_write_register(
thid_t thread_id,
int reg_idx,
const regval_t *value,
qstring *errbuf) override;
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) override;
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &ranges, qstring *errbuf) override;
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
virtual int idaapi handle_ioctl(int fn, const void *buf, size_t size, void **outbuf, ssize_t *outsize) override;
//
win32_debmod_t();
~win32_debmod_t() { cleanup(); }
void handle_pdb_thread_request(void *data);
uint32 calc_imagesize(eanat_t base);
bool get_filename_for(
char *buf,
size_t bufsize,
eanat_t image_name_ea,
bool use_unicode,
eanat_t image_base);
ea_t get_dll_export(
const images_t &dlls,
ea_t imagebase,
const char *exported_name);
bool create_process(
const char *path,
const char *args,
const char *startdir,
bool is_gui,
bool hide_window,
PROCESS_INFORMATION *ProcessInformation);
void show_debug_event(const DEBUG_EVENT &ev);
ssize_t _read_memory(eanat_t ea, void *buffer, size_t size, bool suspend = false);
ssize_t _write_memory(eanat_t ea, const void *buffer, size_t size, bool suspend = false);
int rdmsr(int reg, uint64 *value);
int wrmsr(int reg, uint64 value);
int kldbgdrv_access_msr(struct SYSDBG_MSR *msr, bool write);
// !! OVERWRITTEN METHODS !!
bool refresh_hwbpts();
// Utility methods
gdecode_t handle_exception(debug_event_t *event,
const EXCEPTION_RECORD &er,
bool was_thread_bpt,
bool firsttime);
ssize_t access_memory(eanat_t ea, void *buffer, ssize_t size, bool write, bool suspend);
inline void resume_all_threads(bool raw = false);
inline void suspend_all_threads(bool raw = false);
size_t add_dll(image_info_t &ii);
bool module_present(const char *modname);
HANDLE get_thread_handle(thid_t tid);
static int get_dmi_cb(debmod_t *sess, MODULEENTRY32 *me32, void *ud);
void get_debugged_module_info(modinfo_t *dmi);
int for_each_module(DWORD pid, module_cb_t module_cb, void *ud);
bool myCloseHandle(HANDLE &h);
void cleanup(void);
void restore_original_bytes(ea_t ea, bool really_restore = true);
int save_original_bytes(ea_t ea);
bool set_thread_bpt(thread_info_t &ti, ea_t ea);
bool del_thread_bpt(thread_info_t &ti, ea_t ea);
bool del_thread_bpts(ea_t ea);
bool has_bpt_at(ea_t ea);
bool can_access(ea_t addr);
ea_t get_kernel_bpt_ea(ea_t ea, thid_t tid);
void create_attach_event(debug_event_t *event, bool attached);
void create_start_event(debug_event_t *event);
bool check_for_hwbpt(debug_event_t *event, bool is_stepping=false);
ea_t get_region_info(ea_t ea, memory_info_t *info);
bool get_dll_exports(
const images_t &dlls,
ea_t imagebase,
name_info_t &ni,
const char *exported_name = NULL);
bool get_filename_from_process(
eanat_t name_ea,
bool is_unicode,
char *buf,
size_t bufsize);
bool get_debug_string(const DEBUG_EVENT &ev, char *buf, size_t bufsize);
int add_thread_ranges(
thid_t tid,
images_t &thread_ranges,
images_t &class_ranges);
ea_t get_pe_header(eanat_t imagebase, peheader_t *nh);
bool get_pe_export_name_from_process(
eanat_t imagebase,
char *name,
size_t namesize);
void show_exception_record(const EXCEPTION_RECORD &er, int level=0);
eanat_t pstos0(eanat_t ea);
eanat_t s0tops(eanat_t ea);
bool prepare_to_stop_process(debug_event_t *, const threads_t &);
bool disable_hwbpts();
bool enable_hwbpts();
bool may_write(ea_t ea);
LPVOID correct_exe_image_base(LPVOID base);
bool clear_tbit(thread_info_t &th);
void invalidate_all_contexts(void);
void enqueue_event(const debug_event_t &ev, queue_pos_t pos);
void suspend_running_threads(threadvec_t &suspended);
void resume_suspended_threads(threadvec_t suspended) const;
bool reopen_threads(void);
virtual bool idaapi write_registers(
thid_t thread_id,
int start,
int count,
const regval_t *values) override;
virtual bool idaapi dbg_prepare_broken_connection(void) override;
virtual bool idaapi dbg_continue_broken_connection(pid_t pid) override;
qvector<pdb_remote_session_t*> pdb_remote_sessions;
pdb_remote_session_t *get_pdb_session(int id);
void delete_pdb_session(int id);
protected:
virtual int dbg_freeze_threads_except(thid_t tid) override;
virtual int dbg_thaw_threads_except(thid_t tid) override;
};
ea_t s0tops(ea_t ea);
#endif

View File

@@ -0,0 +1,717 @@
//
//
// This file contains win32 specific implementations of win32_debmod class
//
//
#include <diskio.hpp>
#include "win32_rpc.h"
#include "win32_undoc.h"
#include "dbg_pe_hlp.cpp"
struct impfunc_t
{
const char *name;
void *fptr;
};
#define IMPFUNC(x) { TEXT(#x), &x }
//lint -esym(843,ntdll) -esym(844,ntdll) could be const
static HMODULE ntdll = NULL;
static NtSystemDebugControl_t *NtSystemDebugControl;
static NtLoadDriver_t *NtLoadDriver;
static NtUnloadDriver_t *NtUnloadDriver;
static RtlAdjustPrivilege_t *RtlAdjustPrivilege;
static NtCreateFile_t *NtCreateFile;
static NtDeviceIoControlFile_t *NtDeviceIoControlFile;
static const impfunc_t ntfuncs[] =
{
IMPFUNC(NtSystemDebugControl),
IMPFUNC(NtLoadDriver),
IMPFUNC(NtUnloadDriver),
IMPFUNC(RtlAdjustPrivilege),
IMPFUNC(NtCreateFile),
IMPFUNC(NtDeviceIoControlFile),
};
// To read MSRs, we use a local kernel debugger driver provided by Microsoft.
//lint -esym(843,DriverHandle,DriverPath,DriverName) could be const
//lint -esym(844,DriverHandle) could be pointing to const
static HANDLE DriverHandle = NULL;
static UNICODE_STRING DriverPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES\\kldbgdrv");
static UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"\\Device\\kldbgdrv");
//--------------------------------------------------------------------------
// PE COMMON HELPER FUNCTIONS
#define lread myread // since we can't use loader_failure()
inline void myread(linput_t *li, void *buf, size_t size)
{
int bytes_read = qlread(li, buf, size);
if ( bytes_read != size )
{
int saved_code = qerrcode();
const char *errmsg = qerrstr();
uint64 pos = qltell(li) - bytes_read;
static const char *const format =
"Read error: %s\n"
"(file position 0x%" FMT_64 "X, wanted 0x%" FMT_Z "X bytes, read 0x%X)";
error(format,
saved_code ? errmsg : "read past end of file",
pos,
size,
bytes_read);
}
}
#include "../../ldr/pe/common.cpp"
#define GetMappedFileName_Name "GetMappedFileNameW"
#define GetModuleFileNameEx_Name "GetModuleFileNameExW"
// function prototypes
typedef DWORD (WINAPI *GetMappedFileName_t)(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, DWORD nSize);
typedef DWORD (WINAPI *GetModuleFileNameEx_t)(HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize);
// functions pointers
//lint -esym(843,_GetMappedFileName,_GetModuleFileNameEx) could be const
static GetMappedFileName_t _GetMappedFileName = NULL;
static GetModuleFileNameEx_t _GetModuleFileNameEx = NULL;
// dynamic linking information for PSAPI functions
//lint -esym(843,hPSAPI) -esym(844,hPSAPI) could be const
static HMODULE hPSAPI = NULL;
// dw32 support
//lint -esym(843,system_teb_size) could be const
static DWORD system_teb_size = MEMORY_PAGE_SIZE;
//--------------------------------------------------------------------------
LPVOID win32_debmod_t::correct_exe_image_base(LPVOID base)
{
return base;
}
//--------------------------------------------------------------------------
eanat_t win32_debmod_t::s0tops(eanat_t ea)
{
return ea;
}
//--------------------------------------------------------------------------
eanat_t win32_debmod_t::pstos0(eanat_t ea)
{
return ea;
}
//--------------------------------------------------------------------------
bool win32_debmod_t::prepare_to_stop_process(debug_event_t *, const threads_t &)
{
return true;
}
//--------------------------------------------------------------------------
bool win32_debmod_t::disable_hwbpts()
{
for ( page_bpts_t::iterator p = page_bpts.begin(); p != page_bpts.end(); ++p )
dbg_enable_page_bpt(p, false);
return true;
}
//--------------------------------------------------------------------------
bool win32_debmod_t::enable_hwbpts()
{
for ( page_bpts_t::iterator p = page_bpts.begin(); p != page_bpts.end(); ++p )
dbg_enable_page_bpt(p, true);
return true;
}
//--------------------------------------------------------------------------
bool win32_debmod_t::may_write(ea_t /*ea*/)
{
return true;
}
//--------------------------------------------------------------------------
int win32_debmod_t::describe_stack_segment(
thid_t tid,
images_t &thr_ranges,
images_t &cls_ranges,
const _NT_TIB &tib,
const char *pref) // "x64" for x64 part of wow64 processes
{
int cnt = 1;
char name[MAXSTR];
asize_t size = EA_T(tib.StackBase) - EA_T(tib.StackLimit);
qsnprintf(name, sizeof(name), "%sStack[%08X]", pref, tid);
image_info_t ii_stack(this, EA_T(tib.StackLimit), size, name);
thr_ranges.insert(std::make_pair(ii_stack.base, ii_stack));
ii_stack.name = "STACK";
cls_ranges.insert(std::make_pair(ii_stack.base, ii_stack));
// verify a Stack PAGE_GUARD page exists
ea_t ea_guard = ii_stack.base - MEMORY_PAGE_SIZE;
MEMORY_BASIC_INFORMATION MemoryBasicInformation;
if ( VirtualQueryEx(process_handle, (LPCVOID)(size_t)ea_guard,
&MemoryBasicInformation, sizeof(MemoryBasicInformation)) )
{
if ( MemoryBasicInformation.Protect & PAGE_GUARD ) // a Stack PAGE_GUARD exists
{
qsnprintf(name, sizeof(name), "%sStack_PAGE_GUARD[%08X]", pref, tid);
image_info_t ii_guard(this, ea_guard, MEMORY_PAGE_SIZE, name);
thr_ranges.insert(std::make_pair(ii_guard.base, ii_guard));
ii_guard.name = "STACK";
cls_ranges.insert(std::make_pair(ii_guard.base, ii_guard));
cnt++;
}
}
return cnt;
}
//--------------------------------------------------------------------------
int win32_debmod_t::add_thread_ranges(
thid_t tid,
images_t &thr_ranges,
images_t &cls_ranges)
{
thread_info_t *ti = threads.get(tid);
if ( ti == NULL )
return 0;
// This structure is specific to NT, but stack related records are Win9X compatible
_NT_TIB tib;
ea_t ea_tib = EA_T(ti->lpThreadLocalBase);
if ( _read_memory(ea_tib, &tib, sizeof(tib)) != sizeof(tib) ) // read the TIB
return 0;
// additional test: we verify that TIB->Self contains the TIB's linear address
if ( EA_T(tib.Self) != ea_tib )
return false;
// add TIB range
char name[MAXSTR];
qsnprintf(name, sizeof(name), "TIB[%08X]", tid);
// we suppose the whole page is reserved for the TIB
image_info_t ii_tib(this, ea_tib, system_teb_size, name);
thr_ranges.insert(std::make_pair(ii_tib.base, ii_tib));
int cnt = 0;
const char *pref = "";
if ( check_wow64_process() == WOW64_YES )
{
// Note: This works for Windows versions <= 8.1
// The offset of the 32-bit TEB address within the 64-bit TEB is 0.
// This can be used to directly access the 32-bit TEB of a WOW64 thread
ea_t wow64_tib_ea = *(uint32*)&tib;
struct _NT_TIB32
{
DWORD ExceptionList;
DWORD StackBase;
DWORD StackLimit;
DWORD SubSystemTib;
DWORD FiberData;
DWORD ArbitraryUserPointer;
DWORD Self;
};
_NT_TIB32 tib32;
if ( _read_memory(wow64_tib_ea, &tib32, sizeof(tib32)) == sizeof(tib32) )
{
_NT_TIB tib2;
tib2.StackBase = (PVOID)(eanat_t)tib32.StackBase;
tib2.StackLimit = (PVOID)(eanat_t)tib32.StackLimit;
cnt += describe_stack_segment(tid, thr_ranges, cls_ranges, tib2, pref);
}
pref = "x64";
}
// add stack range
cnt += describe_stack_segment(tid, thr_ranges, cls_ranges, tib, pref);
return cnt;
}
//--------------------------------------------------------------------------
// Get PE header
// In: ea=DLL imagebase, nh=buffer to keep the answer
// child==true:ea is an address in the child process
// child==false:ea is an address in the the debugger itself
// Returns: offset to the headers, BADADDR means failure
ea_t win32_debmod_t::get_pe_header(eanat_t ea, peheader_t *nh)
{
uint32 offset = 0;
uint32 magic;
if ( _read_memory(ea, &magic, sizeof(magic)) != sizeof(magic) )
return BADADDR;
if ( ushort(magic) == MC2('M','Z') )
{
if ( _read_memory(ea+PE_PTROFF, &offset, sizeof(offset)) != sizeof(offset) )
return BADADDR;
}
peheader64_t pe64;
if ( _read_memory(ea+offset, &pe64, sizeof(pe64)) != sizeof(pe64) )
return BADADDR;
if ( !pe64_to_pe(*nh, pe64, true, true) )
return BADADDR;
if ( nh->signature != PEEXE_ID )
return BADADDR;
return offset;
}
//--------------------------------------------------------------------------
// calculate dll image size
// since we could not find anything nice, we just look
// at the beginning of the DLL module in the memory and extract
// correct value from the file header
uint32 win32_debmod_t::calc_imagesize(eanat_t base)
{
peheader_t nh;
ea_t peoff = get_pe_header(base, &nh);
if ( peoff == BADADDR )
return 0;
return nh.imagesize;
}
//--------------------------------------------------------------------------
bool win32_debmod_t::create_process(
const char *path,
const char *args,
const char *startdir,
bool is_gui,
bool hide_window,
PROCESS_INFORMATION *ProcessInformation)
{
linput_t *li = open_linput(path, false);
if ( li == NULL )
return false;
pe_loader_t pl;
pl.read_header(li, true);
close_linput(li);
#ifndef __EA64__
if ( pl.pe.is_pe_plus() )
{
dwarning("AUTOHIDE NONE\nPlease use ida64 to debug 64-bit applications");
SetLastError(ERROR_NOT_SUPPORTED);
return false;
}
#endif
#ifdef __X86__
if ( pl.pe.is_pe_plus() )
{
static const char server_name[] = "win64_remote64.exe";
if ( ask_yn(ASKBTN_YES,
"AUTOHIDE REGISTRY\nHIDECANCEL\n"
"Debugging 64-bit applications is only possible with the %s server.\n"
"Launch it now?",
server_name) == ASKBTN_YES )
{
do
{
// Switch to the remote win32 debugger
if ( !load_debugger("win32_stub", true) )
{
warning("Failed to switch to the remote windows debugger!");
break;
}
// Form the server path
char server_exe[QMAXPATH];
qmakepath(server_exe, sizeof(server_exe), idadir(NULL), server_name, NULL);
// Try to launch the server
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
if ( hide_window )
{
si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; /* SW_FORCEMINIMIZE ? */
}
if ( !::CreateProcess(server_exe, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) )
{
warning("Failed to run the 64-bit remote server!");
break;
}
// Set the remote debugging options: localhost
set_remote_debugger("localhost", "", -1);
// Notify the user
info("Debugging server has been started, please try debugging the program again.");
} while ( false );
}
SetLastError(ERROR_NOT_SUPPORTED);
return false;
}
#endif // __X86__
// Empty directory means our directory
if ( startdir != NULL && startdir[0] == '\0' )
startdir = NULL;
// Args passed as empty string?
if ( args != NULL && args[0] == '\0' )
args = NULL;
launch_process_params_t lpp;
lpp.flags |= LP_TRACE | LP_PATH_WITH_ARGS;
if ( !is_gui )
lpp.flags |= LP_NEW_CONSOLE;
if ( hide_window )
lpp.flags |= LP_HIDE_WINDOW;
lpp.path = path;
lpp.args = args;
lpp.startdir = startdir;
lpp.info = ProcessInformation;
qstring errbuf;
if ( launch_process(lpp, &errbuf) == NULL )
{
dwarning("AUTOHIDE NONE\n%s", errbuf.c_str());
return false;
}
return true;
}
//--------------------------------------------------------------------------
void term_win32_subsystem(void)
{
if ( hPSAPI != NULL )
{
FreeLibrary(hPSAPI);
hPSAPI = NULL;
}
if ( DriverHandle != NULL )
{
CloseHandle(DriverHandle);
DriverHandle = NULL;
NtUnloadDriver(&DriverPath);
}
}
//--------------------------------------------------------------------------
void init_win32_subsystem(void)
{
ntdll = GetModuleHandle(TEXT("ntdll.dll"));
if ( ntdll != NULL )
{
for ( int i=0; i < qnumber(ntfuncs); i++ )
*(FARPROC*)ntfuncs[i].fptr = GetProcAddress(ntdll, ntfuncs[i].name);
}
// load the library
hPSAPI = LoadLibrary(TEXT("psapi.dll"));
if ( hPSAPI != NULL )
{
// find the needed functions
*(FARPROC*)&_GetMappedFileName = GetProcAddress(hPSAPI, TEXT(GetMappedFileName_Name));
*(FARPROC*)&_GetModuleFileNameEx = GetProcAddress(hPSAPI, TEXT(GetModuleFileNameEx_Name));
if ( _GetMappedFileName == NULL )
{
FreeLibrary(hPSAPI);
hPSAPI = NULL;
}
}
}
//--------------------------------------------------------------------------
bool win32_debmod_t::can_access(ea_t addr)
{
char dummy;
return access_memory(addr, &dummy, 1, false, false) == 1;
}
//--------------------------------------------------------------------------
// return the address of all names exported by a DLL in 'ni'
// if 'exported_name' is given, only the address of this exported name will be returned in 'ni'
bool win32_debmod_t::get_pe_exports_from_path(
const char *path,
linput_t *li,
ea_t imagebase,
name_info_t &ni,
const char *exported_name) const
{
// prepare nice name prefix for exported functions names
char prefix[MAXSTR];
qstrncpy(prefix, qbasename(path), sizeof(prefix));
char *ptr = strrchr(prefix, '.');
if ( ptr != NULL )
*ptr = '\0';
qstrlwr(prefix);
pe_loader_t pl;
if ( !pl.read_header(li) )
return false;
struct export_reader_t : public pe_export_visitor_t
{
const char *prefix;
ea_t imagebase;
name_info_t &ni;
const char *exported_name;
export_reader_t(const char *pfx, ea_t base, name_info_t &_ni, const char *exname)
: prefix(pfx), imagebase(base), ni(_ni), exported_name(exname) {}
int idaapi visit_export(uint32 rva, uint32 ord, const char *name, const char *)
{
ea_t fulladdr = imagebase + rva;
if ( exported_name != NULL )
{
if ( strcmp(exported_name, name) == 0 )
{
ni.addrs.push_back(fulladdr);
return 1;
}
}
else
{
qstring n2;
if ( name[0] == '\0' )
n2.sprnt("%s_%u", prefix, ord);
else
n2.sprnt("%s_%s", prefix, name);
ni.addrs.push_back(fulladdr);
ni.names.push_back(n2.extract());
}
return 0;
}
};
export_reader_t er(prefix, imagebase, ni, exported_name);
return pl.process_exports(li, er) >= 0;
}
//--------------------------------------------------------------------------
// return the address of all names exported by a DLL in 'ni'
// if 'exported_name' is given, only the address of this exported name will be returned in 'ni'
bool win32_debmod_t::get_dll_exports(
const images_t &loaded_dlls,
ea_t imagebase,
name_info_t &ni,
const char *exported_name)
{
char prefix[MAXSTR];
images_t::const_iterator p = loaded_dlls.find(imagebase);
if ( p == loaded_dlls.end() )
{
dwarning("get_dll_exports: can't find dll name for imagebase %a", imagebase);
return false;
}
char dname[MAXSTR];
const char *dllname = p->second.name.c_str();
qstrncpy(dname, dllname, sizeof(dname));
if ( debapp_attrs.addrsize == 4 )
replace_system32(dname, MAXSTR);
linput_t *li = open_linput(dname, false);
if ( li == NULL )
{
// sysWOW64: ntdll32.dll does not exist but there is a file called ntdll.dll
if ( stricmp(qbasename(dllname), "ntdll32.dll") != 0 )
return false;
if ( qisabspath(dllname) )
{
qstrncpy(prefix, dllname, sizeof(prefix));
char *fname = qbasename(prefix);
qstrncpy(fname, "ntdll.dll", sizeof(prefix)-(fname-prefix));
dllname = prefix;
}
else
{
#ifdef __X86__
// TODO: On X86 there might by file redirection active on a X64 host
// Therefore we will load on such system always 32 bit DLL, as we can
// access 64 bit one without disabling the redirection
dllname = "C:\\Windows\\System32\\ntdll.dll";
#else
#ifndef __EA64__
dllname = "C:\\Windows\\SysWOW64\\ntdll.dll";
#else
dllname = debapp_attrs.addrsize != 4 ? "C:\\Windows\\System32\\ntdll.dll" : "C:\\Windows\\SysWOW64\\ntdll.dll";
#endif
#endif
}
li = open_linput(dllname, false);
if ( li == NULL )
return false;
}
bool ok = get_pe_exports_from_path(dllname, li, imagebase, ni, exported_name);
close_linput(li);
return ok;
}
//--------------------------------------------------------------------------
// get name from export directory in PE image in debugged process
bool win32_debmod_t::get_pe_export_name_from_process(
eanat_t imagebase,
char *name,
size_t namesize)
{
peheader_t pe;
ea_t peoff = get_pe_header(imagebase, &pe);
if ( peoff != BADADDR && pe.expdir.rva != 0 )
{
eanat_t ea = imagebase + pe.expdir.rva;
peexpdir_t expdir;
if ( _read_memory(ea, &expdir, sizeof(expdir)) == sizeof(expdir) )
{
ea = imagebase + expdir.dllname;
name[0] = '\0';
_read_memory(ea, name, namesize); // don't check the return code because
// we might have read more than necessary
if ( name[0] != '\0' )
return true;
}
}
return false;
}
//--------------------------------------------------------------------------
// Read/write a model specific register using the driver provided by WinDbg.
// The following requirements are imposed by this code:
// - debugger module should be run with admin privileges
// - System must be loaded with /debug switch (use bcdedit.exe to turn it on)
// - Windbg local kernel debugging should be used at least once
// This code is based on a sample kindly provided by Alex Ionescu.
int win32_debmod_t::kldbgdrv_access_msr(SYSDBG_MSR *msr, bool write)
{
NTSTATUS code;
IO_STATUS_BLOCK IoStatusBlock;
if ( DriverHandle == NULL )
{
//
// Acquire 'load driver' privilege
//
BOOLEAN Old;
code = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, TRUE, FALSE, &Old);
if ( FAILED(code) )
{
dwarning("AUTOHIDE NONE\n"
"Failed to acquire 'load driver' privilege, please run as admin!\n"
"Error: %s\n", winerr(code));
return code;
}
//
// And need this for the driver to accept our commands
// Additionally, system must be booted in /DEBUG mode
//
code = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &Old);
if ( FAILED(code) )
{
dwarning("AUTOHIDE NONE\n"
"Failed to acquire 'debug' privilege, is system booted in /debug mode?\n"
"Error: %s\n", winerr(code));
return code;
}
//
// Now load the driver
//
code = NtLoadDriver(&DriverPath);
if ( FAILED(code) && code != STATUS_IMAGE_ALREADY_LOADED )
{
dwarning("AUTOHIDE NONE\n"
"Failed to load 'kldbgdrv', please use local kernel debugging at least once!\n"
"Error: %s\n", winerr(code));
return code;
}
//
// Open a handle to it
//
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes, &DriverName, OBJ_CASE_INSENSITIVE, NULL, NULL);
code = NtCreateFile(&DriverHandle,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_CREATE,
FILE_NON_DIRECTORY_FILE,
NULL,
0);
if ( FAILED(code) )
{
dwarning("AUTOHIDE NONE\n"
"Failed to open 'kldbgdrv'\n"
"Error: %s\n", winerr(code));
return code;
}
}
//
// Package the input parameters into the private structure
//
KLDD_DATA_DEBUG_CONTROL KldDebugCommand;
KldDebugCommand.Command = write ? SysDbgWriteMsr : SysDbgReadMsr;
KldDebugCommand.InputBuffer = msr;
KldDebugCommand.InputBufferLength = sizeof(*msr);
//
// Send the request -- output isn't packaged, just specify directly the buffer
//
code = NtDeviceIoControlFile(DriverHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
KLDD_CODE_DEBUG_CONTROL,
&KldDebugCommand,
sizeof(KldDebugCommand),
msr,
sizeof(*msr));
if ( FAILED(code) )
{
dwarning("AUTOHIDE NONE\n"
"Failed to access model specific register, is system booted in /debug mode?\n"
"Error: %s\n", winerr(code));
return code;
}
// all ok!
return code;
}
//--------------------------------------------------------------------------
int win32_debmod_t::rdmsr(int reg, uint64 *value)
{
SYSDBG_MSR msr;
msr.reg = reg;
msr.value = 0; // shut up the compiler
NTSTATUS code;
if ( NtSystemDebugControl == NULL )
code = STATUS_NOT_IMPLEMENTED;
else
code = NtSystemDebugControl(SysDbgReadMsr, &msr, sizeof(msr), &msr, sizeof(msr), 0);
// if failed to read it with SystemDebugControl, try the driver
if ( FAILED(code) )
code = kldbgdrv_access_msr(&msr, false);
if ( SUCCEEDED(code) )
*value = msr.value;
return code;
}
//--------------------------------------------------------------------------
int win32_debmod_t::wrmsr(int reg, uint64 value)
{
SYSDBG_MSR msr;
msr.reg = reg;
msr.value = value;
NTSTATUS code;
if ( NtSystemDebugControl == NULL )
code = STATUS_NOT_IMPLEMENTED;
else
code = NtSystemDebugControl(SysDbgWriteMsr, &msr, sizeof(msr), NULL, 0, 0);
// if failed to write it with SystemDebugControl, try the driver
if ( FAILED(code) )
code = kldbgdrv_access_msr(&msr, true);
return code;
}

View File

@@ -0,0 +1,208 @@
#ifndef __NT__
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT
#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT
#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP
#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED
#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND
#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO
#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT
#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION
#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW
#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK
#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW
#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO
#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW
#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION
#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR
#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION
#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION
#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW
#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION
#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION
#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE
#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT
#define DBG_CONTROL_C 0x40010005L
#define DBG_CONTROL_BREAK 0x40010008L
#define STATUS_GUARD_PAGE_VIOLATION 0x80000001L
#define STATUS_DATATYPE_MISALIGNMENT 0x80000002L
#define STATUS_BREAKPOINT 0x80000003L
#define STATUS_SINGLE_STEP 0x80000004L
#define STATUS_ACCESS_VIOLATION 0xC0000005L
#define STATUS_IN_PAGE_ERROR 0xC0000006L
#define STATUS_INVALID_HANDLE 0xC0000008L
#define STATUS_NO_MEMORY 0xC0000017L
#define STATUS_ILLEGAL_INSTRUCTION 0xC000001DL
#define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025L
#define STATUS_INVALID_DISPOSITION 0xC0000026L
#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008CL
#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008DL
#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008EL
#define STATUS_FLOAT_INEXACT_RESULT 0xC000008FL
#define STATUS_FLOAT_INVALID_OPERATION 0xC0000090L
#define STATUS_FLOAT_OVERFLOW 0xC0000091L
#define STATUS_FLOAT_STACK_CHECK 0xC0000092L
#define STATUS_FLOAT_UNDERFLOW 0xC0000093L
#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094L
#define STATUS_INTEGER_OVERFLOW 0xC0000095L
#define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096L
#define STATUS_STACK_OVERFLOW 0xC00000FDL
#define STATUS_CONTROL_C_EXIT 0xC000013AL
#define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4L
#define STATUS_FLOAT_MULTIPLE_TRAPS 0xC00002B5L
#define STATUS_REG_NAT_CONSUMPTION 0xC00002C9L
#define SUCCEEDED(x) (x >= 0)
#define FAILED(x) (x < 0)
#endif
#include <expr.hpp>
#include <loader.hpp>
#include "../ldr/pe/pe.h"
#include "../plugins/pdb/pdb.hpp"
#include "win32_rpc.h"
#include "dbg_rpc_hlp.h"
//--------------------------------------------------------------------------
static const char idc_win32_rdmsr_args[] = { VT_LONG, 0 };
static error_t idaapi idc_win32_rdmsr(idc_value_t *argv, idc_value_t *res)
{
uint64 value = 0; // shut up the compiler
uval_t reg = argv[0].num;
#ifdef RPC_CLIENT
void *out = NULL;
ssize_t outsize;
int code = g_dbgmod.send_ioctl(WIN32_IOCTL_RDMSR, &reg, sizeof(reg), &out, &outsize);
if ( SUCCEEDED(code) && outsize == sizeof(value) )
value = *(uint64*)out;
qfree(out);
#else
int code = g_dbgmod.rdmsr(reg, &value);
#endif
if ( FAILED(code) )
{
res->num = code;
return set_qerrno(eExecThrow); // read error, raise exception
}
res->set_int64(value);
return eOk;
}
//--------------------------------------------------------------------------
static const char idc_win32_wrmsr_args[] = { VT_LONG, VT_INT64, 0 };
static error_t idaapi idc_win32_wrmsr(idc_value_t *argv, idc_value_t *res)
{
win32_wrmsr_t msr;
msr.reg = argv[0].num;
msr.value = argv[1].i64;
#ifdef RPC_CLIENT
res->num = g_dbgmod.send_ioctl(WIN32_IOCTL_WRMSR, &msr, sizeof(msr), NULL, NULL);
#else
res->num = g_dbgmod.wrmsr(msr.reg, msr.value);
#endif
return eOk;
}
//--------------------------------------------------------------------------
// Installs or uninstalls debugger specific idc functions
static bool register_idc_funcs(bool reg)
{
static const ext_idcfunc_t idcfuncs[] =
{
{ IDC_READ_MSR, idc_win32_rdmsr, idc_win32_rdmsr_args, NULL, 0, 0 },
{ IDC_WRITE_MSR, idc_win32_wrmsr, idc_win32_wrmsr_args, NULL, 0, 0 },
};
return add_idc_funcs(idcfuncs, qnumber(idcfuncs), reg);
}
//--------------------------------------------------------------------------
void idaapi rebase_if_required_to(ea_t new_base)
{
netnode penode(PE_NODE);
ea_t currentbase = new_base;
ea_t imagebase = ea_t(penode.altval(PE_ALT_IMAGEBASE)); // loading address (usually pe.imagebase)
if ( imagebase == 0 )
{
if ( !is_miniidb() )
warning("AUTOHIDE DATABASE\n"
"IDA could not automatically determine if the program should be\n"
"rebased in the database because the database format is too old and\n"
"doesn't contain enough information.\n"
"Create a new database if you want automated rebasing to work properly.\n"
"Note you can always manually rebase the program by using the\n"
"Edit, Segments, Rebase program command.");
}
else if ( imagebase != currentbase )
{
rebase_or_warn(imagebase, currentbase);
}
}
//--------------------------------------------------------------------------
bool read_pe_header(peheader_t *pe)
{
netnode penode(PE_NODE);
return penode.valobj(pe, sizeof(peheader_t)) > 0;
}
//--------------------------------------------------------------------------
// Initialize Win32 debugger plugin
static bool win32_init_plugin(void)
{
// Remote debugger? Then nothing to initialize locally
#ifndef RPC_CLIENT
if ( !init_subsystem() )
return false;
#endif
if ( !netnode::inited() || is_miniidb() || inf_is_snapshot() )
{
#ifndef __NT__
// local debugger is available if we are running under Windows
// for other systems only the remote debugger is available
if ( !debugger.is_remote() )
return false;
#endif
}
else
{
if ( inf_get_filetype() != f_PE )
return false; // only PE files
processor_t &ph = PH;
if ( ph.id != TARGET_PROCESSOR && ph.id != -1 )
return false;
// find out the pe header
peheader_t pe;
if ( !read_pe_header(&pe) )
return false;
// debug only gui, console, or unknown applications
if ( pe.subsys != PES_WINGUI // Windows GUI
&& pe.subsys != PES_WINCHAR // Windows Character
&& pe.subsys != PES_UNKNOWN ) // Unknown
{
return false;
}
}
return true;
}
//--------------------------------------------------------------------------
inline void win32_term_plugin(void)
{
#ifndef RPC_CLIENT
term_subsystem();
#endif
}
//----------------------------------------------------------------------------
struct pdb_remote_session_t;
void close_pdb_remote_session(pdb_remote_session_t *)
{
}
#ifndef HAVE_PLUGIN_COMMENTS
//--------------------------------------------------------------------------
static const char comment[] = "Userland win32 debugger plugin";
#endif

View File

@@ -0,0 +1,203 @@
#ifndef WIN32_RPC_H
#define WIN32_RPC_H
// IOCTL codes for the win32 debugger
#define WIN32_IOCTL_RDMSR 0 // read model specific register
#define WIN32_IOCTL_WRMSR 1 // write model specific register
#define WIN32_IOCTL_READFILE 2 // server->client: read bytes from the input file
// uint64 offset;
// uint32 length;
// returns: 1 - ok
// -2 - error (text in output buffer)
// Open file for PDB retrieval.
//
// This operation will *typically* require that executable data
// be provided to the underlying MS PDB "DIA" dll. Therefore,
// there is _no_ way (currently) that this operation will
// immediately return something relevant. The client must
// poll for _OPERATION_COMPLETE-ness.
//
// client->server
// (unpacked) compiler_info_t: compiler_info
// (packed) uint64 : base_address
// (unpacked) char * : input_file
// (unpacked) char * : user symbols path
// server->client
// (packed) uint32 : session handle
#define WIN32_IOCTL_PDB_OPEN 3
// Close PDB 'session', previously opened with _PDB_OPEN.
//
// client->server
// (packed) uint32 : session handle
// server->client
// void
#define WIN32_IOCTL_PDB_CLOSE 4
// Fetch the data for one symbol.
//
// Synchronous operation.
//
// client->server
// (packed) uint32 : session handle
// (packed) uint64 : symbol ID
// server->client
// (unpacked) uint32: The integer value 1.
// (serialized) data: Packed symbol data (once).
#define WIN32_IOCTL_PDB_FETCH_SYMBOL 5
// Fetch the data for the children of a symbol.
//
// Synchronous operation.
//
// client->server
// (packed) uint32 : session handle
// (packed) uint64 : symbol ID
// (packed) uint32 : children type (a SymTagEnum)
// server->client
// (unpacked) uint32: Number of symbols whose data
// has been fetched.
// (serialized) data: Packed symbol data (N times).
#define WIN32_IOCTL_PDB_FETCH_CHILDREN 6
// Is the current operation complete?
//
// Depending on the type of the operation, the contents
// of the results will differ:
// - _OPEN
// (packed) uint64 : Global symbol ID.
// (packed) uint32 : machine type.
// (packed) uint32 : DIA version.
//
// NOTE: Currently, this IOCTL only makes sense to check
// for completeness of operation _OPEN, but this
// might change in the future.
//
// client->server
// (packed) uint32 : session handle
// server->client
// (packed) uint32 : See pdb_op_completion_t
// Depending on this first byte, the following will be come:
// pdb_op_not_complete:
// nothing
// pdb_op_complete:
// (packed) uint32 : global symbol ID
// (packed) uint32 : machine type
// (packed) uint32 : DIA version
// (unpacked) str : used file name
// pdb_op_failure:
// (unpacked) str : error message
#define WIN32_IOCTL_PDB_OPERATION_COMPLETE 7
// Get lines by VA
//
// client->server
// (packed) uint32 : session handle
// (packed) ea_t : VA
// (packed) uint64 : length
// server->client
// (packed) uint32 : the number of line-number objects
// (packed) data : the line-number objects (N times)
//
// Each of the line-number objects is transmitted like so:
// (packed) ea_t : VA
// (packed) uint32 : length
// (packed) uint32 : columnNumber
// (packed) uint32 : columnNumberEnd
// (packed) uint32 : lineNumber
// (packed) uint32 : lineNumberEnd
// (packed) uint32 : file_id
// (unpacked) byte : statement
#define WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA 8
// Get lines by coordinates
//
// client->server
// (packed) uint32 : session handle
// (packed) uint32 : file ID
// (packed) uint32 : lnnum
// (packed) uint32 : colnum
// server->client
// same as WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA
#define WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_COORDS 9
// Get symbols at EA
//
// client->server
// (packed) uint32 : session handle
// (packed) ea_t : VA
// (packed) uint64 : length
// (packed) uint32 : children type (a SymTagEnum)
// server->client
// (unpacked) uint32: Number of symbols whose data
// has been fetched.
// (serialized) data: Packed symbol data (N times).
#define WIN32_IOCTL_PDB_SIP_FETCH_SYMBOLS_AT_VA 10
// Get compilands for file
//
// client->server
// (packed) uint32 : session handle
// (packed) uint32 : file ID
// server->client
// (unpacked) uint32: Number of symbols whose data
// has been fetched.
// (serialized) data: Packed symbol data (N times).
#define WIN32_IOCTL_PDB_SIP_FETCH_FILE_COMPILANDS 11
// Get path for file ID
//
// client->server
// (packed) uint32 : session handle
// (packed) uint32 : file ID
// server->client
// (unpacked) str : the path
#define WIN32_IOCTL_PDB_SIP_FETCH_FILE_PATH 12
// Get files IDs for files corresponding to symbol
//
// client->server
// (packed) uint32 : session handle
// (packed) uint64 : symbol ID
// server->client
// (packed) uint32 : the number of IDs
// (packed) uint32 : file ID (N times).
#define WIN32_IOCTL_PDB_SIP_FETCH_SYMBOL_FILES 13
// Get files IDs for files whose name matches
//
// client->server
// (packed) uint32 : session handle
// (unpacked) str : the file name
// server->client
// (packed) uint32 : the number of IDs
// (packed) uint32 : file ID (N times).
#define WIN32_IOCTL_PDB_SIP_FIND_FILES 14
enum ioctl_pdb_code_t
{
pdb_ok = 1,
pdb_error = -2,
};
enum pdb_op_completion_t
{
pdb_op_not_complete = 0,
pdb_op_complete = 1,
pdb_op_failure = -1,
};
// WIN32_IOCTL_WRMSR uses this structure:
struct win32_wrmsr_t
{
uint32 reg;
uint64 value;
};
#endif // WIN32_RPC_H

View File

@@ -0,0 +1,406 @@
//
//
// This file contains win32 specific implementations of win32_debugger_module class
// server-side functionality only
//
//
#include <pro.h>
#include "win32_rpc.h"
#include "win32_debmod.h"
#include "dbg_rpc_hlp.h"
bool ida_export idb_utf8(qstring *, const char *, int, int) { return false; }
#include "tilfuncs.hpp"
//---------------------------------------------------------- main thread ---
static AS_PRINTF(3, 4) int pdb_ioctl_error(void **poutbuf, ssize_t *poutsize, const char *format, ...)
{
char buf[MAXSTR];
va_list va;
va_start(va, format);
int len = qvsnprintf(buf, sizeof(buf), format, va);
va_end(va);
msg("%s", buf);
*poutsize = len + 1;
*poutbuf = qstrdup(buf);
return pdb_error;
}
//---------------------------------------------------------- main thread ---
void win32_debmod_t::handle_pdb_thread_request(void *_pdb_rsess)
{
pdb_remote_session_t *pdb_rsess = (pdb_remote_session_t *) _pdb_rsess;
pdb_remote_session_t::client_read_request_t &rr = pdb_rsess->client_read_request;
if ( rr.kind == READ_INPUT_FILE )
{
// read input file
bytevec_t req;
req.pack_dq(rr.off_ea);
req.pack_dd(rr.size);
void *outbuf = NULL;
ssize_t outsize = 0;
// send request to IDA
int rc = send_ioctl(WIN32_IOCTL_READFILE, req.begin(), req.size(), &outbuf, &outsize);
if ( rc == 1 && outbuf != NULL )
{
// OK
size_t copylen = qmin(rr.size, outsize);
memcpy(rr.buffer, outbuf, copylen);
rr.size = copylen;
rr.result = true;
}
else
{
rr.result = false;
}
if ( outbuf != NULL )
qfree(outbuf);
}
else if ( rr.kind == READ_MEMORY )
{
// read memory
ea_t ea = ea_t(rr.off_ea);
void *buf = rr.buffer;
size_t size = rr.size;
ssize_t rc = _read_memory(ea, buf, size);
if ( rc >= 0 )
rr.size = rc;
rr.result = rc >= 0;
}
else
{
// unknown request
rr.result = false;
}
rr.read_complete();
}
//-------------------------------------------------------------------------
pdb_remote_session_t *win32_debmod_t::get_pdb_session(int id)
{
for ( size_t i = 0; i < pdb_remote_sessions.size(); ++i )
if ( pdb_remote_sessions[i]->get_id() == id )
return pdb_remote_sessions[i];
return NULL;
}
//-------------------------------------------------------------------------
void win32_debmod_t::delete_pdb_session(int id)
{
for ( size_t i = 0; i < pdb_remote_sessions.size(); ++i )
{
if ( pdb_remote_sessions[i]->get_id() == id )
{
pdb_remote_sessions[i]->stop();
delete pdb_remote_sessions[i];
pdb_remote_sessions.erase(pdb_remote_sessions.begin() + i);
break;
}
}
}
//----------------------------------------------------------------------------
void close_pdb_remote_session(pdb_remote_session_t *session)
{
session->stop();
delete session;
}
//---------------------------------------------------------- main thread ---
int idaapi win32_debmod_t::handle_ioctl(
int fn,
const void *buf,
size_t size,
void **poutbuf,
ssize_t *poutsize)
{
qnotused(size);
int sid = 0; // pdb_remote_session_t ID
pdb_remote_session_t *pdb_rsess = NULL;
switch ( fn )
{
case WIN32_IOCTL_RDMSR:
QASSERT(30119, size == sizeof(uval_t));
{
uint64 value;
uval_t reg = *(uval_t *)buf;
int code = rdmsr(reg, &value);
if ( SUCCEEDED(code) )
{
*poutbuf = qalloc(sizeof(value));
if ( *poutbuf != NULL )
{
memcpy(*poutbuf, &value, sizeof(value));
*poutsize = sizeof(value);
}
}
return code;
}
case WIN32_IOCTL_WRMSR:
QASSERT(30120, size == sizeof(win32_wrmsr_t));
{
win32_wrmsr_t &msr = *(win32_wrmsr_t *)buf;
return wrmsr(msr.reg, msr.value);
}
#define ENSURE_PDB_THREAD() \
do \
{ \
if ( !pdb_thread.is_running() ) \
return pdb_ioctl_error( \
poutbuf, poutsize, "PDB thread not running?!?\n"); \
} while ( false )
#define GET_OPENED_SESSION() \
do \
{ \
if ( mmdsr.empty() ) \
return pdb_error; \
sid = mmdsr.unpack_dd(); \
pdb_rsess = get_pdb_session(sid); \
} while ( false )
#define ENSURE_SESSION_OPENED() \
do \
{ \
GET_OPENED_SESSION(); \
if ( pdb_rsess == NULL ) \
return pdb_ioctl_error( \
poutbuf, poutsize, "Unknown PDB session #%d\n", sid); \
} while ( false )
#define FLUSH_PDB_REQUEST_STORAGE() \
do \
{ \
size_t sz = pdb_rsess->storage.size(); \
uint8 *raw = (uint8 *) qalloc(sz); \
if ( raw == NULL ) \
return pdb_error; \
memcpy(raw, pdb_rsess->storage.begin(), sz); \
*poutbuf = raw; \
*poutsize = sz; \
} while ( false )
case WIN32_IOCTL_PDB_OPEN:
{
pdb_thread.start_if_needed();
memory_deserializer_t mmdsr(buf, size);
pdb_rsess = new pdb_remote_session_t();
pdb_remote_sessions.push_back(pdb_rsess);
compiler_info_t cci;
mmdsr.unpack_obj(&cci, sizeof(cci));
pdbargs_t args;
args.pdb_path = mmdsr.unpack_str();
args.input_path = mmdsr.unpack_str();
mmdsr.unpack_obj(&args.pdb_sign, sizeof(args.pdb_sign));
args.spath = mmdsr.unpack_str();
args.loaded_base = mmdsr.unpack_ea64();
args.flags = mmdsr.unpack_dd();
pdb_rsess->open(cci, args);
bytevec_t storage;
storage.pack_dd(pdb_rsess->get_id());
*poutsize = storage.size();
*poutbuf = storage.extract();
pdb_rsess->is_opening = true;
}
return pdb_ok;
case WIN32_IOCTL_PDB_OPERATION_COMPLETE:
// This is used, in a polling fashion, by the the client,
// to check on completeness of the fetch. At the same time,
// this is our wake-up call for looking whether the
// fetch thread requires more information.
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
// If we've got a read request, handle it now
if ( pdb_rsess->client_read_request.pending() )
handle_pdb_thread_request(pdb_rsess);
bytevec_t storage;
bool done = pdb_rsess->is_done();
if ( done )
{
pdb_rsess->is_opening = false;
const char *fname = pdb_rsess->session_ref.session->get_used_fname();
local_pdb_access_t *acc = pdb_rsess->session_ref.session->pdb_access;
HRESULT hr = acc != NULL ? S_OK : E_FAIL;
if ( SUCCEEDED(hr) )
{
storage.pack_dd(uint32(pdb_op_complete));
storage.pack_dd(acc->get_global_symbol_id());
storage.pack_dd(acc->get_machine_type());
storage.pack_dd(acc->get_dia_version());
storage.pack_str(fname);
}
else
{
storage.pack_dd(uint32(pdb_op_failure));
qstring errmsg;
errmsg.sprnt("%s: %s\n", fname, pdberr(hr));
storage.pack_str(errmsg.c_str());
delete_pdb_session(sid);
}
}
else
{
storage.pack_dd(uint32(pdb_op_not_complete));
}
*poutsize = storage.size();
*poutbuf = storage.extract();
return pdb_ok;
}
case WIN32_IOCTL_PDB_FETCH_SYMBOL:
case WIN32_IOCTL_PDB_FETCH_CHILDREN:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
DWORD sym_id = mmdsr.unpack_dd();
// msg("Fetch%s 0x%x\n",
// (fn == WIN32_IOCTL_PDB_FETCH_CHILDREN ? " children for" : ""),
// (uint32) sym);
bool ok;
if ( fn == WIN32_IOCTL_PDB_FETCH_SYMBOL )
{
// Symbol
ok = pdb_rsess->fetch_symbol(sym_id);
}
else
{
// Children
enum SymTagEnum children_type = (enum SymTagEnum) mmdsr.unpack_dd();
ok = pdb_rsess->fetch_children(sym_id, children_type);
}
if ( ok )
FLUSH_PDB_REQUEST_STORAGE();
return ok ? pdb_ok : pdb_error;
}
case WIN32_IOCTL_PDB_CLOSE:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
GET_OPENED_SESSION();
if ( pdb_rsess != NULL )
delete_pdb_session(sid);
return pdb_ok;
}
case WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
ea_t va = mmdsr.unpack_ea64();
uint64 length = mmdsr.unpack_dq();
bool ok = pdb_rsess->fetch_lines_by_va(
va, length);
if ( ok )
FLUSH_PDB_REQUEST_STORAGE();
return ok ? pdb_ok : pdb_error;
}
case WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_COORDS:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
DWORD file_id = mmdsr.unpack_dd();
DWORD lnnum = mmdsr.unpack_dd();
DWORD colnum = mmdsr.unpack_dd();
bool ok = pdb_rsess->fetch_lines_by_coords(file_id, lnnum, colnum);
if ( ok )
FLUSH_PDB_REQUEST_STORAGE();
return ok ? pdb_ok : pdb_error;
}
case WIN32_IOCTL_PDB_SIP_FETCH_SYMBOLS_AT_VA:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
ea_t va = mmdsr.unpack_ea64();
uint64 length = mmdsr.unpack_dq();
enum SymTagEnum type = (enum SymTagEnum) mmdsr.unpack_dd();
bool ok = pdb_rsess->fetch_symbols_at_va(va, length, type);
if ( ok )
FLUSH_PDB_REQUEST_STORAGE();
return ok ? pdb_ok : pdb_error;
}
case WIN32_IOCTL_PDB_SIP_FETCH_FILE_COMPILANDS:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
uint32 file_id = mmdsr.unpack_dd();
bool ok = pdb_rsess->fetch_file_compilands(file_id);
if ( ok )
FLUSH_PDB_REQUEST_STORAGE();
return ok ? pdb_ok : pdb_error;
}
case WIN32_IOCTL_PDB_SIP_FETCH_FILE_PATH:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
uint32 file_id = mmdsr.unpack_dd();
bool ok = pdb_rsess->fetch_file_path(file_id);
if ( ok )
FLUSH_PDB_REQUEST_STORAGE();
return ok ? pdb_ok : pdb_error;
}
case WIN32_IOCTL_PDB_SIP_FETCH_SYMBOL_FILES:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
DWORD sym_id = mmdsr.unpack_dd();
bool ok = pdb_rsess->fetch_symbol_files(sym_id);
if ( ok )
FLUSH_PDB_REQUEST_STORAGE();
return ok ? pdb_ok : pdb_error;
}
case WIN32_IOCTL_PDB_SIP_FIND_FILES:
{
ENSURE_PDB_THREAD();
memory_deserializer_t mmdsr(buf, size);
ENSURE_SESSION_OPENED();
qstring fname = mmdsr.unpack_str();
bool ok = pdb_rsess->fetch_files(fname.c_str());
if ( ok )
FLUSH_PDB_REQUEST_STORAGE();
return ok ? pdb_ok : pdb_error;
}
default:
break;
}
return 0;
}

View File

@@ -0,0 +1,15 @@
//
//
// This file contains win32 specific implementations of win32_debugger_module class
// IDA-side functionality only (for local debugger)
//
//
#include <pro.h>
#include "win32_debmod.h"
//--------------------------------------------------------------------------
int idaapi win32_debmod_t::handle_ioctl(int /*fn*/, const void * /*buf*/, size_t /*size*/, void ** /*poutbuf*/, ssize_t * /*poutsize*/)
{
return 0;
}

View File

@@ -0,0 +1,128 @@
#define REMOTE_DEBUGGER
#define RPC_CLIENT
static const char wanted_name[] = "Remote Windows debugger";
#define DEBUGGER_NAME "win32"
#define PROCESSOR_NAME "metapc"
#define DEFAULT_PLATFORM_NAME "win32"
#define TARGET_PROCESSOR PLFM_386
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_WIN32_USER
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
| DBG_FLAG_EXITSHOTOK \
| DBG_FLAG_LOWCNDS \
| DBG_FLAG_DEBTHREAD \
| DBG_FLAG_ANYSIZE_HWBPT)
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
#define HAVE_APPCALL
#define S_FILETYPE f_PE
#define win32_term_plugin term_plugin
#include <pro.h>
#include <idp.hpp>
#include <idd.hpp>
#include <ua.hpp>
#include <range.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <network.hpp>
#include "w32sehch.h"
#include "dbg_rpc_client.h"
#include "rpc_debmod.h"
class win32_rpc_debmod_t : public rpc_debmod_t
{
typedef rpc_debmod_t inherited;
public:
win32_rpc_debmod_t(const char *default_platform)
: rpc_debmod_t(default_platform) {}
virtual bool idaapi open_remote(
const char *hostname,
int port_number,
const char *password,
qstring *errbuf) override
{
char path[QMAXPATH];
get_input_file_path(path, sizeof(path));
pdb_file_path = path;
return inherited::open_remote(hostname, port_number, password, errbuf);
}
qstring pdb_file_path;
};
win32_rpc_debmod_t g_dbgmod(DEFAULT_PLATFORM_NAME);
#include "common_stub_impl.cpp"
#include "pc_local_impl.cpp"
#include "win32_local_impl.cpp"
//--------------------------------------------------------------------------
// handler on IDA: Server -> IDA
static int ioctl_handler(
rpc_engine_t * /*rpc*/,
int fn,
const void *buf,
size_t size,
void **poutbuf,
ssize_t *poutsize)
{
qnotused(size);
switch ( fn )
{
case WIN32_IOCTL_READFILE:
{
user_cancelled();
const uchar *ptr = (const uchar *)buf;
const uchar *end = ptr + size;
uint64 offset = unpack_dq(&ptr, end);
uint32 length = unpack_dd(&ptr, end);
*poutbuf = NULL;
*poutsize = 0;
if ( length != 0 )
{
FILE *infile = qfopen(g_dbgmod.pdb_file_path.c_str(), "rb");
if ( infile == NULL )
return -2;
void *outbuf = qalloc(length);
if ( outbuf == NULL )
return -2;
qfseek(infile, offset, SEEK_SET);
int readlen = qfread(infile, outbuf, length);
qfclose(infile);
if ( readlen < 0 || readlen > length )
{
qfree(outbuf);
return -2;
}
*poutbuf = outbuf;
*poutsize = readlen;
}
return 1;
}
}
return 0;
}
//lint -esym(528,init_plugin) static symbol '' not referenced
//--------------------------------------------------------------------------
// Initialize Win32 debugger stub
static bool init_plugin(void)
{
// There is no need to call win32_init_plugin() (which checks the PE
// file parameters) if the debugger is only being used to fetch PDBs.
bool should_init = !netnode(PDB_NODE_NAME).altval(PDB_LOADING_WIN32_DBG);
if ( should_init && !win32_init_plugin() )
return false;
g_dbgmod.set_ioctl_handler(ioctl_handler);
return true;
}
#include "common_local_impl.cpp"

View File

@@ -0,0 +1,282 @@
#ifndef WIN32_UNDOC_H
#define WIN32_UNDOC_H
// Definitions for Windows DDK and other undocumented MS Windows types.
// Instead of requiring a DDK and NDK, we just use this file.
//---------------------------------------------------------------------------
// WinDDK types
struct UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWCH Buffer;
};
typedef UNICODE_STRING *PUNICODE_STRING;
extern "C" char _RTL_CONSTANT_STRING_type_check(const WCHAR *s);
// __typeof would be desirable here instead of sizeof.
template <size_t N> class _RTL_CONSTANT_STRING_remove_const_template_class;
template <> class _RTL_CONSTANT_STRING_remove_const_template_class<sizeof(char)>
{
public:
typedef char T;
};
template <> class _RTL_CONSTANT_STRING_remove_const_template_class<sizeof(WCHAR)>
{
public:
typedef WCHAR T;
};
#define _RTL_CONSTANT_STRING_remove_const_macro(s) \
(const_cast<_RTL_CONSTANT_STRING_remove_const_template_class<sizeof((s)[0])>::T*>(s))
#define RTL_CONSTANT_STRING(s) \
{ \
sizeof(s) - sizeof((s)[0]), \
sizeof(s) / sizeof(_RTL_CONSTANT_STRING_type_check(s)), \
_RTL_CONSTANT_STRING_remove_const_macro(s) \
}
typedef struct _OBJECT_ATTRIBUTES64
{
ULONG Length;
ULONG64 RootDirectory;
ULONG64 ObjectName;
ULONG Attributes;
ULONG64 SecurityDescriptor;
ULONG64 SecurityQualityOfService;
} OBJECT_ATTRIBUTES64;
typedef OBJECT_ATTRIBUTES64 *POBJECT_ATTRIBUTES64;
typedef CONST OBJECT_ATTRIBUTES64 *PCOBJECT_ATTRIBUTES64;
typedef struct _OBJECT_ATTRIBUTES32
{
ULONG Length;
ULONG RootDirectory;
ULONG ObjectName;
ULONG Attributes;
ULONG SecurityDescriptor;
ULONG SecurityQualityOfService;
} OBJECT_ATTRIBUTES32;
typedef OBJECT_ATTRIBUTES32 *POBJECT_ATTRIBUTES32;
typedef CONST OBJECT_ATTRIBUTES32 *PCOBJECT_ATTRIBUTES32;
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;
#define InitializeObjectAttributes(p,n,a,r,s) \
{ \
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
(p)->RootDirectory = (r); \
(p)->Attributes = (a); \
(p)->ObjectName = (n); \
(p)->SecurityDescriptor = (s); \
(p)->SecurityQualityOfService = NULL; \
}
//
// Definitions for Object Creation
//
#define OBJ_INHERIT 0x00000002L
#define OBJ_PERMANENT 0x00000010L
#define OBJ_EXCLUSIVE 0x00000020L
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define OBJ_OPENIF 0x00000080L
#define OBJ_OPENLINK 0x00000100L
#define OBJ_KERNEL_HANDLE 0x00000200L
#define OBJ_FORCE_ACCESS_CHECK 0x00000400L
#define OBJ_VALID_ATTRIBUTES 0x000007F2L
//---------------------------------------------------------------------------
// Undocumented types - pulled out of MS Windows NDK by Alex Ionecsu
//
// Privilege constants
//
#define SE_MIN_WELL_KNOWN_PRIVILEGE (2L)
#define SE_CREATE_TOKEN_PRIVILEGE (2L)
#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE (3L)
#define SE_LOCK_MEMORY_PRIVILEGE (4L)
#define SE_INCREASE_QUOTA_PRIVILEGE (5L)
#define SE_UNSOLICITED_INPUT_PRIVILEGE (6L)
#define SE_MACHINE_ACCOUNT_PRIVILEGE (6L)
#define SE_TCB_PRIVILEGE (7L)
#define SE_SECURITY_PRIVILEGE (8L)
#define SE_TAKE_OWNERSHIP_PRIVILEGE (9L)
#define SE_LOAD_DRIVER_PRIVILEGE (10L)
#define SE_SYSTEM_PROFILE_PRIVILEGE (11L)
#define SE_SYSTEMTIME_PRIVILEGE (12L)
#define SE_PROF_SINGLE_PROCESS_PRIVILEGE (13L)
#define SE_INC_BASE_PRIORITY_PRIVILEGE (14L)
#define SE_CREATE_PAGEFILE_PRIVILEGE (15L)
#define SE_CREATE_PERMANENT_PRIVILEGE (16L)
#define SE_BACKUP_PRIVILEGE (17L)
#define SE_RESTORE_PRIVILEGE (18L)
#define SE_SHUTDOWN_PRIVILEGE (19L)
#define SE_DEBUG_PRIVILEGE (20L)
#define SE_AUDIT_PRIVILEGE (21L)
#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L)
#define SE_CHANGE_NOTIFY_PRIVILEGE (23L)
#define SE_REMOTE_SHUTDOWN_PRIVILEGE (24L)
#define SE_MAX_WELL_KNOWN_PRIVILEGE (SE_REMOTE_SHUTDOWN_PRIVILEGE)
// Undocumented NTSystemDebugControl function (to read/write MSRs)
enum SYSDBG_COMMAND
{
SysDbgQueryModuleInformation = 1,
SysDbgQueryTraceInformation = 2,
SysDbgSetTracepoint = 3,
SysDbgSetSpecialCall = 4,
SysDbgClearSpecialCalls = 5,
SysDbgQuerySpecialCalls = 6,
SysDbgReadMsr = 16,
SysDbgWriteMsr = 17,
};
struct SYSDBG_MSR
{
uint32 reg;
uint32 padding;
uint64 value;
};
#define NTSTATUS int
#ifndef NTAPI
#define NTAPI WINAPI
#endif
#ifndef STATUS_NOT_IMPLEMENTED
#define STATUS_NOT_IMPLEMENTED 0xC0000002
#endif
#ifndef STATUS_IMAGE_ALREADY_LOADED
#define STATUS_IMAGE_ALREADY_LOADED 0xC000010E
#endif
//
// NtCreateFile OpenType Flags
//
#define FILE_SUPERSEDE 0x00000000
#define FILE_OPEN 0x00000001
#define FILE_CREATE 0x00000002
#define FILE_OPEN_IF 0x00000003
#define FILE_OVERWRITE 0x00000004
#define FILE_OVERWRITE_IF 0x00000005
#define FILE_MAXIMUM_DISPOSITION 0x00000005
//
// NtCreateFile Flags
//
#define FILE_DIRECTORY_FILE 0x00000001
#define FILE_WRITE_THROUGH 0x00000002
#define FILE_SEQUENTIAL_ONLY 0x00000004
#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008
#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
#define FILE_NON_DIRECTORY_FILE 0x00000040
#define FILE_CREATE_TREE_CONNECTION 0x00000080
#define FILE_COMPLETE_IF_OPLOCKED 0x00000100
#define FILE_NO_EA_KNOWLEDGE 0x00000200
#define FILE_OPEN_FOR_RECOVERY 0x00000400
#define FILE_RANDOM_ACCESS 0x00000800
#define FILE_DELETE_ON_CLOSE 0x00001000
#define FILE_OPEN_BY_FILE_ID 0x00002000
#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
#define FILE_NO_COMPRESSION 0x00008000
#define FILE_RESERVE_OPFILTER 0x00100000
#define FILE_OPEN_REPARSE_POINT 0x00200000
#define FILE_OPEN_NO_RECALL 0x00400000
#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
//
// Interface for communicating with private WinDBG interface
//
#define KLDD_CODE_DEBUG_CONTROL \
CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
typedef struct _KLDD_DATA_DEBUG_CONTROL
{
SYSDBG_COMMAND Command;
PVOID InputBuffer;
SIZE_T InputBufferLength;
} KLDD_DATA_DEBUG_CONTROL, *PKLDD_DATA_DEBUG_CONTROL;
//
// I/O Status Block
//
typedef struct _IO_STATUS_BLOCK
{
union
{
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
//
// APC Callback for NtDeviceIoControlFile
//
typedef VOID
(NTAPI *PIO_APC_ROUTINE)(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved);
typedef NTSTATUS NTAPI NtSystemDebugControl_t(
IN SYSDBG_COMMAND Command,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength,
OUT PULONG ReturnLength OPTIONAL);
typedef NTSTATUS NTAPI NtLoadDriver_t(
IN PUNICODE_STRING DriverServiceName);
typedef NTSTATUS NTAPI NtUnloadDriver_t(
IN PUNICODE_STRING DriverServiceName);
typedef NTSTATUS NTAPI RtlAdjustPrivilege_t(
IN ULONG Privilege,
IN BOOLEAN NewValue,
IN BOOLEAN ForThread,
OUT PBOOLEAN OldValue);
typedef NTSTATUS NTAPI NtCreateFile_t(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength);
typedef NTSTATUS NTAPI NtDeviceIoControlFile_t(
IN HANDLE DeviceHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
IN PVOID UserApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG IoControlCode,
IN PVOID InputBuffer,
IN ULONG InputBufferSize,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferSize);
#endif // define WIN32_UNDOC_H

View File

@@ -0,0 +1,46 @@
/*
This is main source code for the local win32 debugger module
*/
static const char wanted_name[] = "Local Windows debugger";
#define DEBUGGER_NAME "win32"
#define PROCESSOR_NAME "metapc"
#define TARGET_PROCESSOR PLFM_386
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_WIN32_USER
#define DEBUGGER_FLAGS (DBG_FLAG_EXITSHOTOK \
| DBG_FLAG_LOWCNDS \
| DBG_FLAG_DEBTHREAD \
| DBG_FLAG_ANYSIZE_HWBPT)
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
#define HAVE_APPCALL
#define S_FILETYPE f_PE
// We must rename those method because common files
// refer to them as init_plugin/term_plugin
// Some other debugger modules compatible with win32
// have their own init/term and still call win32_init/term
// (since no renaming takes place)
#define win32_init_plugin init_plugin
#define win32_term_plugin term_plugin
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <objidl.h>
#include <fpro.h>
#include <ua.hpp>
#include <idd.hpp>
#include <loader.hpp>
#include "win32_debmod.h"
#include "w32sehch.h"
win32_debmod_t g_dbgmod;
#include "common_stub_impl.cpp"
#include "pc_local_impl.cpp"
#include "win32_local_impl.cpp"
#include "common_local_impl.cpp"
#include "win32_server_stub.cpp"

View File

@@ -0,0 +1,87 @@
#include <windows.h>
#include <pro.h>
#include "winbase_debmod.h"
#include "win32_util.hpp"
#ifndef __X86__
typedef BOOL WINAPI IsWow64Process_t(HANDLE, PBOOL);
static IsWow64Process_t *_IsWow64Process = NULL;
#endif
//--------------------------------------------------------------------------
//lint -esym(818,handle) could be pointer to const
wow64_state_t check_wow64_handle(HANDLE handle)
{
#ifdef __X86__
qnotused(handle);
#else
if ( _IsWow64Process == NULL )
{
HMODULE k32 = GetModuleHandle(kernel32_dll);
*(FARPROC*)&_IsWow64Process = GetProcAddress(k32, TEXT("IsWow64Process"));
if ( _IsWow64Process == NULL )
return WOW64_NONE; // unknown
}
BOOL bIsWow64 = FALSE;
if ( _IsWow64Process(handle, &bIsWow64) && bIsWow64 != 0 )
return WOW64_YES;
#endif
return WOW64_NO;
}
//--------------------------------------------------------------------------
wow64_state_t check_wow64_pid(int pid)
{
wow64_state_t r = WOW64_BAD; // assume pid is bad
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if ( h != NULL )
{
r = check_wow64_handle(h);
CloseHandle(h);
}
return r;
}
//--------------------------------------------------------------------------
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4996) // GetVersionEx was declared deprecated
#endif
win_version_t::win_version_t()
{
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
ver_ok = GetVersionEx(&OSVersionInfo) != 0; //lint !e2586 is deprecated
#ifdef __X86__
is_64bit_os = false;
if ( OSVersionInfo.dwMajorVersion > 5
|| OSVersionInfo.dwMajorVersion == 5 && OSVersionInfo.dwMinorVersion >= 1 )
{
is_64bit_os = check_wow64_handle(GetCurrentProcess()) > 0;
}
#endif
}
#ifdef _MSC_VER
# pragma warning(pop)
#endif
//--------------------------------------------------------------------------
win_tool_help_t::win_tool_help_t()
{
use_debug_break = qgetenv("IDA_DEBUGBREAKPROCESS");
HMODULE kern_handle = GetModuleHandle(kernel32_dll);
*(FARPROC*)&_DebugActiveProcessStop = GetProcAddress(kern_handle, TEXT("DebugActiveProcessStop"));
*(FARPROC*)&_DebugBreakProcess = GetProcAddress(kern_handle, TEXT("DebugBreakProcess"));
// find the needed functions
*(FARPROC*)&_CreateToolhelp32Snapshot = GetProcAddress(kern_handle, TEXT("CreateToolhelp32Snapshot"));
*(FARPROC*)&_Process32First = GetProcAddress(kern_handle, TEXT("Process32First"));
*(FARPROC*)&_Process32Next = GetProcAddress(kern_handle, TEXT("Process32Next"));
*(FARPROC*)&_Module32First = GetProcAddress(kern_handle, TEXT("Module32First"));
*(FARPROC*)&_Module32Next = GetProcAddress(kern_handle, TEXT("Module32Next"));
inited = _CreateToolhelp32Snapshot != NULL
&& _Process32First != NULL
&& _Process32Next != NULL
&& _Module32First != NULL
&& _Module32Next != NULL;
}

View File

@@ -0,0 +1,347 @@
//
// Wrapper for Windows ToolHelp library: enumerate processes/modules
//
// PSAPI.DLL: NT, 2K, XP/2K3
// KERNEL32.DLL (ToolHelp functions): 9X, ME, 2K, XP/2K3
//? add NT support
#ifndef __TOOLHELP_HPP__
#define __TOOLHELP_HPP__
#ifdef __NT__
#include <windows.h>
#include <Tlhelp32.h>
#include <dbghelp.h>
#include <segment.hpp>
#ifdef UNICODE
#define LookupPrivilegeValue_Name "LookupPrivilegeValueW"
#else
#define LookupPrivilegeValue_Name "LookupPrivilegeValueA"
#endif
#ifndef TH32CS_SNAPNOHEAPS
# define TH32CS_SNAPNOHEAPS 0x0
#endif
//--------------------------------------------------------------------------
enum wow64_state_t
{
WOW64_NONE = -2, // unknown yet
WOW64_BAD = -1,
WOW64_NO = 0,
WOW64_YES = 1,
};
wow64_state_t check_wow64_handle(HANDLE handle);
wow64_state_t check_wow64_pid(int pid);
//--------------------------------------------------------------------------
class win_version_t
{
public:
win_version_t();
const OSVERSIONINFO &get_info() const { return OSVersionInfo; }
bool ok() { return ver_ok; }
bool is_NT()
{
return ok() && OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT;
}
bool is_strictly_xp() // Is strictly XP (32bit)?
{
return ok()
&& is_NT()
&& OSVersionInfo.dwMajorVersion == 5
&& OSVersionInfo.dwMinorVersion == 1;
}
bool is_DW32()
{
return ok() && OSVersionInfo.dwPlatformId == 3;
}
bool is_2K() // Is at least Win2K?
{
return ok() && OSVersionInfo.dwMajorVersion >= 5;
}
bool is_64bitOS()
{
#ifndef __X86__
return true;
#else
return is_64bit_os;
#endif
}
//--------------------------------------------------------------------------
// GetProcessDEPPolicy() is broken for Win8, Win8.1, Win10:
// always set *lpPermanent == CL register, if not permanently policy.
// https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/05683d76-3c8a-49de-91e3-9d7ab8492f39/getprocessdeppolicy-does-not-set-the-correct-value-to-lppermanent?forum=windowscompatibility
bool is_GetProcessDEPPolicy_broken()
{
return ok()
&& ((OSVersionInfo.dwMajorVersion == 10 && OSVersionInfo.dwMinorVersion == 0) // Windows 10
|| (OSVersionInfo.dwMajorVersion == 6 && OSVersionInfo.dwMinorVersion == 3) // Windows 8.1
|| (OSVersionInfo.dwMajorVersion == 6 && OSVersionInfo.dwMinorVersion == 2)); // Windows 8
}
private:
OSVERSIONINFO OSVersionInfo;
bool ver_ok;
#ifdef __X86__
bool is_64bit_os;
#endif
};
//--------------------------------------------------------------------------
//-V:win_tool_help_t:730 Not all members of a class are initialized inside the constructor
class win_tool_help_t
{
public:
win_tool_help_t();
bool ok() { return inited; }
bool use_debug_break_process();
bool debug_break_process(HANDLE process_handle);
bool use_debug_detach_process();
bool debug_detach_process(pid_t pid);
private:
// function prototypes
typedef HANDLE WINAPI CreateToolhelp32Snapshot_t(DWORD dwFlags, DWORD th32ProcessID);
typedef BOOL WINAPI Process32First_t(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
typedef BOOL WINAPI Process32Next_t(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
typedef BOOL WINAPI Module32First_t(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
typedef BOOL WINAPI Module32Next_t(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
typedef BOOL WINAPI DebugActiveProcessStop_t(DWORD dwProcessID);
typedef BOOL WINAPI DebugBreakProcess_t(HANDLE Process);
typedef BOOL WINAPI CloseToolhelp32Snapshot_t(HANDLE hSnapshot);
// functions pointers
CreateToolhelp32Snapshot_t *_CreateToolhelp32Snapshot;
Process32First_t *_Process32First;
Process32Next_t *_Process32Next;
Module32First_t *_Module32First;
Module32Next_t *_Module32Next;
DebugActiveProcessStop_t *_DebugActiveProcessStop;
DebugBreakProcess_t *_DebugBreakProcess;
bool inited;
bool use_debug_break;
friend class toolhelp_snapshot_t;
friend class process_snapshot_t;
friend class module_snapshot_t;
};
//--------------------------------------------------------------------------
class toolhelp_snapshot_t
{
public:
inline toolhelp_snapshot_t(win_tool_help_t *tool);
inline ~toolhelp_snapshot_t();
inline bool ok();
inline bool open(uint32 flags, pid_t pid);
inline void close();
inline uint32 last_err();
protected:
bool seterr(); // always returns 'false' for convenience
win_tool_help_t *t;
HANDLE h;
uint32 last_error;
};
//--------------------------------------------------------------------------
class process_snapshot_t: public toolhelp_snapshot_t
{
public:
inline process_snapshot_t(win_tool_help_t *tool);
inline bool first(uint32 flags, LPPROCESSENTRY32 lppe);
inline bool next(LPPROCESSENTRY32 lppe);
};
//--------------------------------------------------------------------------
class module_snapshot_t: public toolhelp_snapshot_t
{
public:
inline module_snapshot_t(win_tool_help_t *tool);
inline bool first(uint32 flags, pid_t pid, LPMODULEENTRY32 lpme);
inline bool next(LPMODULEENTRY32 lpme);
};
//--------------------------------------------------------------------------
inline bool win_tool_help_t::use_debug_break_process()
{
return use_debug_break && _DebugBreakProcess != NULL;
}
//--------------------------------------------------------------------------
inline bool win_tool_help_t::debug_break_process(HANDLE process_handle)
{
return process_handle != INVALID_HANDLE_VALUE && _DebugBreakProcess(process_handle);
}
//--------------------------------------------------------------------------
inline bool win_tool_help_t::use_debug_detach_process()
{
return _DebugActiveProcessStop != NULL;
}
//--------------------------------------------------------------------------
inline bool win_tool_help_t::debug_detach_process(pid_t pid)
{
return _DebugActiveProcessStop != NULL && _DebugActiveProcessStop(pid);
}
//--------------------------------------------------------------------------
inline process_snapshot_t::process_snapshot_t(win_tool_help_t *tool)
: toolhelp_snapshot_t(tool)
{
}
//--------------------------------------------------------------------------
inline bool process_snapshot_t::first(uint32 flags, LPPROCESSENTRY32 lppe)
{
open(TH32CS_SNAPPROCESS | flags, 0);
lppe->dwSize = sizeof(PROCESSENTRY32);
if ( ok() && t->_Process32First(h, lppe) )
{
// ignore "System Process" (ID==0)
return lppe->th32ProcessID != 0 || next(lppe);
}
return seterr();
}
//--------------------------------------------------------------------------
inline bool process_snapshot_t::next(LPPROCESSENTRY32 lppe)
{
while ( ok() )
{
if ( !t->_Process32Next(h, lppe) )
break;
// ignore "System Process" (ID==0)
if ( lppe->th32ProcessID != 0 )
return true;
}
return seterr();
}
//--------------------------------------------------------------------------
inline module_snapshot_t::module_snapshot_t(win_tool_help_t *tool)
: toolhelp_snapshot_t(tool)
{
}
//--------------------------------------------------------------------------
inline bool module_snapshot_t::first(uint32 flags, pid_t pid, LPMODULEENTRY32 lpme)
{
wow64_state_t state = check_wow64_pid(pid);
flags |= state == WOW64_YES ? TH32CS_SNAPMODULE32 : 0;
if ( !open(TH32CS_SNAPMODULE | flags, pid) )
return false;
lpme->dwSize = sizeof(MODULEENTRY32);
if ( t->_Module32First(h, lpme) )
return true;
return seterr();
}
//--------------------------------------------------------------------------
inline bool module_snapshot_t::next(LPMODULEENTRY32 lpme)
{
if ( ok() )
return false;
if ( t->_Module32Next(h, lpme) )
return true;
seterr();
return false;
}
//--------------------------------------------------------------------------
inline toolhelp_snapshot_t::toolhelp_snapshot_t(win_tool_help_t *tool)
: t(tool), h(INVALID_HANDLE_VALUE), last_error(0)
{
}
//--------------------------------------------------------------------------
inline toolhelp_snapshot_t::~toolhelp_snapshot_t()
{
close();
}
//--------------------------------------------------------------------------
inline bool toolhelp_snapshot_t::ok()
{
return h != INVALID_HANDLE_VALUE;
}
//--------------------------------------------------------------------------
// // always returns 'false' for convenience
inline bool toolhelp_snapshot_t::seterr()
{
last_error = GetLastError();
return false;
}
//--------------------------------------------------------------------------
// // always returns 'false' for convenience
inline uint32 toolhelp_snapshot_t::last_err()
{
return last_error;
}
//--------------------------------------------------------------------------
inline bool toolhelp_snapshot_t::open(uint32 flags, pid_t pid)
{
if ( !t->ok() )
return false;
close();
for ( int cnt=0; cnt < 5; cnt++ )
{
h = t->_CreateToolhelp32Snapshot(flags, pid);
if ( h != INVALID_HANDLE_VALUE )
return true;
seterr();
// MSDN: If the function fails with ERROR_BAD_LENGTH, retry
// the function until it succeeds.
if ( last_err() != ERROR_BAD_LENGTH
|| (flags & (TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32)) == 0 )
{
break;
}
}
return false;
}
//--------------------------------------------------------------------------
inline void toolhelp_snapshot_t::close()
{
if ( t->ok() && h != INVALID_HANDLE_VALUE )
CloseHandle(h);
}
//--------------------------------------------------------------------------
// convert Windows protection modes to IDA protection modes
inline uchar win_prot_to_ida_perm(DWORD protection)
{
uchar perm = 0;
if ( protection & PAGE_READONLY )
perm |= SEGPERM_READ;
if ( protection & PAGE_READWRITE )
perm |= SEGPERM_READ | SEGPERM_WRITE;
if ( protection & PAGE_WRITECOPY )
perm |= SEGPERM_READ | SEGPERM_WRITE;
if ( protection & PAGE_EXECUTE )
perm |= SEGPERM_EXEC;
if ( protection & PAGE_EXECUTE_READ )
perm |= SEGPERM_READ | SEGPERM_EXEC;
if ( protection & PAGE_EXECUTE_READWRITE )
perm |= SEGPERM_READ | SEGPERM_WRITE | SEGPERM_EXEC;
if ( protection & PAGE_EXECUTE_WRITECOPY )
perm |= SEGPERM_READ | SEGPERM_WRITE | SEGPERM_EXEC;
return perm;
}
#endif // __NT__
#endif // __TOOLHELP_HPP__

View File

@@ -0,0 +1,619 @@
#include <windows.h>
#include <ida.hpp>
#include "winbase_debmod.h"
#ifndef __X86__
#define IDA_ADDRESS_SIZE 8
#else
#define IDA_ADDRESS_SIZE 4
#endif
const TCHAR kernel32_dll[] = TEXT("kernel32.dll");
typedef BOOL WINAPI GetProcessDEPPolicy_t(HANDLE hProcess, LPDWORD lpFlags, PBOOL lpPermanent);
static GetProcessDEPPolicy_t *_GetProcessDEPPolicy = NULL;
typedef dep_policy_t WINAPI GetSystemDEPPolicy_t(void);
static GetSystemDEPPolicy_t *_GetSystemDEPPolicy = NULL;
//--------------------------------------------------------------------------
winbase_debmod_t::winbase_debmod_t(void)
: is_wow64(WOW64_NONE),
process_handle(INVALID_HANDLE_VALUE),
dep_policy(dp_always_off),
highdlls()
{
HMODULE k32 = GetModuleHandle(kernel32_dll);
if ( _GetProcessDEPPolicy == NULL )
*(FARPROC*)&_GetProcessDEPPolicy = GetProcAddress(k32, TEXT("GetProcessDEPPolicy"));
if ( _GetSystemDEPPolicy == NULL )
*(FARPROC*)&_GetSystemDEPPolicy = GetProcAddress(k32, TEXT("GetSystemDEPPolicy"));
if ( _GetSystemDEPPolicy != NULL )
dep_policy = _GetSystemDEPPolicy();
win_tool_help = NULL;
set_platform("win32");
}
//--------------------------------------------------------------------------
// Prepare new page protections for a breakpoint of BPTTYPE.
// Use INPUT as starting page protections.
// Return false in the case of failure.
bool winbase_debmod_t::remove_page_protections(
DWORD *p_input,
bpttype_t bpttype,
dep_policy_t dpolicy,
HANDLE proc_handle)
{
// If PAGE_GUARD is already set, do not change anything, it is already ok
DWORD input = *p_input;
if ( (input & PAGE_GUARD) != 0 )
return false;
// Convert between Unix permissions and Win32 page protections using this array:
static const uchar win32_page_protections[] =
{
PAGE_NOACCESS, // 000
PAGE_READONLY, // 001
0xFF, // 010 WRITE_ONLY does not exist on win32
PAGE_READWRITE, // 011
PAGE_EXECUTE, // 100
PAGE_EXECUTE_READ, // 101
0xFF, // 110 EXECUTE_WRITE does not exist on win32
PAGE_EXECUTE_READWRITE, // 111
};
uchar unix;
// convert ..COPY page protections into their non-copy counterparts
// this is the best thing we can do with them because they are automatically
// converted by the system upon a write access
if ( (input & PAGE_WRITECOPY) != 0 )
{
unix = 3; // rw
}
else if ( (input & PAGE_EXECUTE_WRITECOPY) != 0 )
{
unix = 7; // rwx
}
else
{
for ( unix=0; unix < 8; unix++ )
{
uchar p = win32_page_protections[unix];
if ( p != 0xFF && (input & p) != 0 )
break;
}
}
QASSERT(622, unix < 8);
// convert bpttype into unix permissions
int del = 0;
if ( (bpttype & BPT_READ) != 0 )
del |= 1;
if ( (bpttype & BPT_WRITE) != 0 )
del |= 2;
if ( (bpttype & BPT_EXEC) != 0 )
{
del |= 4;
// if DEP is disabled for this process then a program can
// happily execute code in a read only area so we need to
// remove *all* privileges, unfortunately
if ( dpolicy != dp_always_on )
{
// on XP, GetProcessDEPPolicy returns DEP policy for current process (i.e. the debugger)
// so we can't use it
// assume that DEP is disabled by default
DWORD flags = 0;
BOOL permanent = 0;
if ( _GetProcessDEPPolicy == NULL
|| winver.is_strictly_xp()
|| winver.is_GetProcessDEPPolicy_broken()
|| _GetProcessDEPPolicy(proc_handle, &flags, &permanent) )
{
// flags == 0: DEP is disabled for the specified process.
//
// Remarks: if permanent == 0 and global DEP policy is OptIn
// flags may be equal to 1 *but* having DEP disabled because,
// in case the process called SetProcessDEPPolicy the
// permanent argument would be 1, it seems to be a bug in the
// documentation
if ( (dpolicy == dp_opt_in && permanent == 0) || flags == 0 )
del |= 1;
}
}
}
// Remove the access types to trigger on
unix &= ~del;
// Handle WRITE_ONLY and EXECUTE_WRITE cases because win32 does not have them.
// We use stricter page permissions for them. This means that there will
// be more useless exceptions but we cannot do much about it.
if ( unix == 2 || unix == 6 )
unix = 0; // use PAGE_NOACCESS instead of WRITE_ONLY or EXECUTE_WRITE
uchar perm = win32_page_protections[unix];
*p_input = (input & ~0xFF) | perm;
return true;
}
//--------------------------------------------------------------------------
bool idaapi winbase_debmod_t::dbg_enable_page_bpt(
page_bpts_t::iterator p,
bool enable)
{
pagebpt_data_t &bpt = p->second;
if ( (bpt.old_prot != 0) == enable )
return false; // already the desired state
debdeb("dbg_enable_page_bpt(%s): page_ea=%a, old_prot=0x%x, new_prot=0x%x\n", enable ? "true" : "false", bpt.page_ea, bpt.old_prot, bpt.new_prot);
DWORD old;
DWORD prot = enable ? bpt.new_prot : bpt.old_prot;
if ( !VirtualProtectEx(process_handle, (void*)(size_t)bpt.page_ea,
bpt.real_len, prot, &old) )
{
deberr("VirtualProtectEx");
// if the page disappeared while disabling a bpt, do not complain,
// silently return success
if ( enable )
return false;
old = 0;
}
debdeb(" success! old=0x%x\n", old);
bpt.old_prot = enable ? old : 0;
return true;
}
//--------------------------------------------------------------------------
// Should we generate a BREAKPOINT event because of page bpt?
//lint -e{1746} could be made const reference
bool should_fire_page_bpt(
page_bpts_t::iterator p,
ea_t ea,
DWORD failed_access_type,
ea_t pc,
dep_policy_t dep_policy)
{
const pagebpt_data_t &bpt = p->second;
if ( !interval::contains(bpt.ea, bpt.user_len, ea) )
return false; // not in the user-defined interval
int bit;
switch ( failed_access_type )
{
default:
INTERR(623); //-V796 no break
case EXCEPTION_READ_FAULT: // failed READ access
// depending on the DEP policy we mark this access also
// to be triggered in case of EXEC breakpoints
bit = BPT_READ;
if ( dep_policy != dp_always_on && bpt.type == BPT_EXEC && pc == ea )
bit |= BPT_EXEC;
break;
case EXCEPTION_WRITE_FAULT: // failed WRITE access
bit = BPT_WRITE;
break;
case EXCEPTION_EXECUTE_FAULT: // failed EXECUTE access
bit = BPT_EXEC;
break;
}
return (bpt.type & bit) != 0;
}
//--------------------------------------------------------------------------
// returns 0-failure, 2-success
int idaapi winbase_debmod_t::dbg_add_page_bpt(
bpttype_t type,
ea_t ea,
int size)
{
// only one page breakpoint per page is permitted
page_bpts_t::iterator p = find_page_bpt(ea, size);
if ( p != page_bpts.end() )
return 0; // another page bpt exists
// Find out the current page protections
MEMORY_BASIC_INFORMATION meminfo;
ea_t page_ea = calc_page_base(ea);
if ( !VirtualQueryEx(process_handle, (void *)(size_t)page_ea,
&meminfo, sizeof(meminfo)) )
{
deberr("VirtualQueryEx");
return 0;
}
// Make sure the page is loaded
if ( (meminfo.State & MEM_FREE) != 0 )
{
deberr("%a: the page has not been allocated", page_ea);
return 0;
}
// According to MSDN documentation for VirtualQueryEx
// (...)
// AllocationProtect
// The memory protection option when the region was initially allocated. This member can be
// one of the memory protection constants or 0 if the caller does not have access.
//
// Unfortunately, there is no more information about why it my happen so, for now, I'm just
// returning an error.
if ( meminfo.Protect == 0 )
{
deberr("%a: the page cannot be accessed", page_ea);
return 0;
}
// Calculate new page protections
int aligned_len = align_up((ea-page_ea)+size, MEMORY_PAGE_SIZE);
int real_len = 0;
DWORD prot = meminfo.Protect;
if ( remove_page_protections(&prot, type, dep_policy, process_handle) )
{ // We have to set new protections
real_len = aligned_len;
}
// Remember the new breakpoint
p = page_bpts.insert(std::make_pair(page_ea, pagebpt_data_t())).first;
pagebpt_data_t &bpt = p->second;
bpt.ea = ea;
bpt.user_len = size;
bpt.page_ea = page_ea;
bpt.aligned_len = aligned_len;
bpt.real_len = real_len;
bpt.old_prot = 0;
bpt.new_prot = prot;
bpt.type = type;
// for PAGE_GUARD pages, no need to change the permissions, everything is fine already
if ( real_len == 0 )
{
bpt.old_prot = meminfo.Protect;
return 2;
}
return dbg_enable_page_bpt(p, true) ? 2 : 0;
}
//--------------------------------------------------------------------------
// returns true if changed *protect (in other words, if we have to mask
// the real page protections and return the original one)
bool winbase_debmod_t::mask_page_bpts(
ea_t startea,
ea_t endea,
uint32 *protect)
{
// if we have page breakpoints, what we return must be changed to show the
// real segment privileges, instead of the new ones we applied for the bpt
int newprot = 0;
page_bpts_t::iterator p = page_bpts.begin();
while ( p != page_bpts.end() )
{
pagebpt_data_t &pbd = p->second;
if ( pbd.page_ea + pbd.real_len > startea )
{
if ( pbd.page_ea >= endea )
break;
if ( pbd.old_prot != 0 )
{ // bpt has been written to the process memory
if ( *protect == pbd.new_prot )
{ // return the old protection, before setting the page bpt
newprot = pbd.old_prot;
}
else
{
debdeb("mask_page_bpts: app changed our page protection for %a (expected: 0x%x, actual: 0x%x)\n", pbd.page_ea, pbd.new_prot, *protect);
// page protection has been changed by the application
DWORD prot = *protect;
if ( prot == PAGE_WRITECOPY && pbd.new_prot == PAGE_READWRITE
|| prot == PAGE_EXECUTE_WRITECOPY && pbd.new_prot == PAGE_EXECUTE_READWRITE )
{
// in some cases OS may restore WRITECOPY protection; do nothing in such cases since it works the same way for breakpoint purposes
debdeb(" ignoring changes to WRITECOPY protection\n");
}
else if ( remove_page_protections(&prot, pbd.type, dep_policy, process_handle) )
{
pbd.new_prot = prot;
pbd.old_prot = 0; // mark our bpt as non-written
debdeb(" will re-set protection to 0x%x\n", pbd.new_prot);
}
}
}
}
++p;
}
if ( newprot != 0 )
{
*protect = newprot;
return true;
}
return false;
}
//--------------------------------------------------------------------------
// Page breakpoints modify the page protections to induce access violations.
// We must hide the modified page protections from IDA and report the original
// page protections.
// Second, the application may render a page bpt inactive by changing its page protections.
// In this case we must report to IDA the new page protections and also reactivate
// the page breakpoint.
void winbase_debmod_t::verify_page_protections(
meminfo_vec_t *areas,
const win32_prots_t &prots)
{
QASSERT(624, areas->size() == prots.size());
if ( page_bpts.empty() )
return;
for ( int i = 0; i < areas->size(); i++ )
{
uint32 prot = prots[i];
memory_info_t &a = areas->at(i);
if ( mask_page_bpts(a.start_ea, a.end_ea, &prot) )
a.perm = win_prot_to_ida_perm(prot);
}
// reactivate all disabled page bpts, if any
enable_page_bpts(true);
}
//--------------------------------------------------------------------------
#ifndef __X86__
wow64_state_t winbase_debmod_t::check_wow64_process()
{
if ( is_wow64 == WOW64_NONE )
{
is_wow64 = check_wow64_handle(process_handle);
if ( is_wow64 > 0 )
dmsg("WOW64 process has been detected (pid=%d)\n", pid);
}
return is_wow64;
}
#endif
//--------------------------------------------------------------------------
bool highdll_vec_t::has(eanat_t addr) const
{
for ( int i = 0; i < size(); ++i )
if ( (*this)[i].has(addr) )
return true;
return false;
}
//--------------------------------------------------------------------------
bool highdll_vec_t::add(eanat_t addr, size_t sz, HANDLE h)
{
if ( has(addr) )
return false;
// check removed: on new win10 we can have above 4GB:
// ntdll.dll, wow64.dll, wow64win.dll
// QASSERT(1491, size() < 2);
highdll_range_t &r = push_back();
r.start = addr;
r.end = addr + sz;
r.handle = h;
return true;
}
//--------------------------------------------------------------------------
bool highdll_vec_t::add_high_module(
eanat_t addr,
size_t sz,
HANDLE h)
{
if ( ea_t(addr) == addr )
return false;
add(addr, sz, h); //-V779 unreachable code
return true;
}
//--------------------------------------------------------------------------
bool highdll_vec_t::del_high_module(HANDLE *h, eanat_t addr)
{
for ( int i = 0; i < size(); ++i )
{
const highdll_range_t &r = (*this)[i];
if ( r.start == addr )
{
if ( h != NULL )
*h = r.handle;
erase(begin() + i);
return ea_t(addr) != addr;
}
}
return false;
}
//--------------------------------------------------------------------------
void idaapi winbase_debmod_t::dbg_term(void)
{
is_wow64 = WOW64_NONE;
delete win_tool_help;
win_tool_help = NULL;
}
//--------------------------------------------------------------------------
// Check if we need to install a temporary breakpoint to workaround the
// 'freely running after syscall' problem. Exactly, the problem is the
// following: after single stepping over a "jmp far ptr" instruction in
// wow64cpu.dll for a 32bits process under a 64bits OS (Win7), the trap flag
// is lost. Probably, it's a bug in wow64cpu!CpuReturnFromSimulatedCode.
//
// So, if we find an instruction like "call large dword fs:XX" we add a
// temporary breakpoint at the next instruction and re-enable tracing
// when the breakpoint is reached.
bool winbase_debmod_t::check_for_call_large(
const debug_event_t *event,
HANDLE handle)
{
if ( check_wow64_handle(handle) <= 0 )
return false;
uchar buf[3];
if ( dbg_read_memory(event->ea, buf, 3, NULL) == 3 )
{
// is it the call large instruction?
if ( memcmp(buf, "\x64\xFF\x15", 3) == 0 )
return true;
}
return false;
}
//--------------------------------------------------------------------------
// Get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
int idaapi winbase_debmod_t::get_process_bitness(int _pid)
{
if ( _pid != -1 && _pid != GetCurrentProcessId() )
{
if ( !winver.is_64bitOS() )
return 4;
switch ( check_wow64_pid(_pid) )
{
case WOW64_BAD: return 0; // bad process id
case WOW64_YES: return 4; // wow64 process, 32bit
case WOW64_NO: return 8; // regular 64bit process
default: break;
}
}
return IDA_ADDRESS_SIZE;
}
//--------------------------------------------------------------------------
static const char *str_bitness(int addrsize)
{
switch ( addrsize )
{
case 8:
return "[64]";
case 4:
return "[32]";
default:
return "[x]";
}
}
//--------------------------------------------------------------------------
// this function may correct pinfo->addrsize
bool winbase_debmod_t::get_process_path(
ext_process_info_t *pinfo,
char *buf,
size_t bufsize)
{
module_snapshot_t msnap(get_tool_help());
MODULEENTRY32 me;
if ( !msnap.first(TH32CS_SNAPMODULE, pinfo->pid, &me) )
{
if ( msnap.last_err() == ERROR_PARTIAL_COPY && pinfo->addrsize == 0 )
{
// MSDN: If the specified process is a 64-bit process and the caller is a
// 32-bit process, error code is ERROR_PARTIAL_COPY
pinfo->addrsize = 8;
}
qstrncpy(buf, pinfo->name.c_str(), bufsize);
return false;
}
else
{
tchar_utf8(buf, me.szExePath, bufsize);
return true;
}
}
//--------------------------------------------------------------------------
win_tool_help_t *winbase_debmod_t::get_tool_help()
{
if ( win_tool_help == NULL )
win_tool_help = new win_tool_help_t;
return win_tool_help;
}
//-------------------------------------------------------------------------
int winbase_debmod_t::get_process_addrsize(pid_t _pid)
{
int addrsize = get_process_bitness(_pid);
return addrsize != 0 ? addrsize : IDA_ADDRESS_SIZE;
}
//--------------------------------------------------------------------------
//lint -e{1762} could be made const [in fact it cannot be made const in x64 mode]
bool winbase_debmod_t::is_ntdll_name(const char *path)
{
const char *base_name = qbasename(path);
const char *ntdll_name = winver.is_NT()
? "ntdll.dll" // NT
: "kernel32.dll"; // 9X/Me and KERNEL32.DLL
if ( strieq(base_name, ntdll_name) )
return true;
#ifndef __X86__
if ( winver.is_NT()
&& check_wow64_process() == WOW64_YES
&& strieq(base_name, "ntdll32.dll") )
{
return true;
}
#endif
return false;
}
//--------------------------------------------------------------------------
//lint -esym(1762,winbase_debmod_t::build_process_ext_name) could be made const
void winbase_debmod_t::build_process_ext_name(ext_process_info_t *pinfo)
{
char fullname[MAXSTR];
if ( get_process_path(pinfo, fullname, sizeof(fullname))
&& pinfo->addrsize == 0 )
{
// the WOW64 is optional on R2 x64 server
pinfo->addrsize = IDA_ADDRESS_SIZE;
}
pinfo->ext_name = str_bitness(pinfo->addrsize);
if ( !pinfo->ext_name.empty() )
pinfo->ext_name += ' ';
pinfo->ext_name += fullname;
}
//--------------------------------------------------------------------------
int idaapi winbase_debmod_t::get_process_list(procvec_t *list, qstring *)
{
int mypid = GetCurrentProcessId();
list->clear();
process_snapshot_t psnap(get_tool_help());
PROCESSENTRY32 pe32;
for ( bool ok = psnap.first(TH32CS_SNAPNOHEAPS, &pe32); ok; ok = psnap.next(&pe32) )
{
if ( pe32.th32ProcessID != mypid )
{
int addrsize = get_process_bitness(pe32.th32ProcessID);
#ifndef __EA64__
if ( addrsize > 4 )
continue; // skip 64bit processes, we cannot debug them because ea_t is 32bit
#endif
ext_process_info_t pinfo;
pinfo.pid = pe32.th32ProcessID;
pinfo.addrsize = addrsize;
tchar_utf8(&pinfo.name, pe32.szExeFile);
build_process_ext_name(&pinfo);
list->push_back(pinfo);
}
}
return list->size();
}
//--------------------------------------------------------------------------
// Returns the file name assciated with pid
bool idaapi winbase_debmod_t::get_exec_fname(int _pid, char *buf, size_t bufsize)
{
ext_process_info_t pinfo;
pinfo.pid = _pid;
pinfo.name.qclear();
return get_process_path(&pinfo, buf, bufsize);
}
//--------------------------------------------------------------------------
win_tool_help_t *winbase_debmod_t::win_tool_help = NULL;
win_version_t winbase_debmod_t::winver;

View File

@@ -0,0 +1,179 @@
#ifndef __WINBASE_HPP__
#define __WINBASE_HPP__
// Base class for win32 and windbg modules
#include <algorithm>
#include <map>
using std::for_each;
using std::pair;
using std::make_pair;
//--------------------------------------------------------------------------
#define BASE_DEBUGGER_MODULE pc_debmod_t
#include "deb_pc.hpp"
#include "pc_debmod.h"
#define BPT_CODE_SIZE X86_BPT_SIZE
#include "win32_util.hpp"
extern const TCHAR kernel32_dll[];
//--------------------------------------------------------------------------
// DEP policies
enum dep_policy_t
{
dp_always_off,
dp_always_on,
dp_opt_in,
dp_opt_out
};
//--------------------------------------------------------------------------
enum attach_status_t
{
as_none, // no attach to process requested
as_attaching, // waiting for CREATE_PROCESS_DEBUG_EVENT, indicating the process is attached
as_breakpoint, // waiting for first breakpoint, indicating the process was properly initialized and suspended
as_attached, // process was successfully attached
as_detaching, // waiting for next get_debug_event() request, to return the process as detached
as_attach_kernel, // attaching to kernel
};
// vector of win32 page protections
// we need this type because meminfo_t does not contain the original win32 protections
// but we need them to verify page bpts
typedef qvector<uint32> win32_prots_t;
//--------------------------------------------------------------------------
// When debugging WOW64 processes with ida32 we have to take into account
// ntdll.dll (and wow64*.dll), which are x64 files
// that can be loaded into high addresses (above 4GB)
// Since ea_t cannot represent such addresses,
// we use our own type to remember the DLL boundaries
typedef size_t eanat_t;
struct highdll_range_t
{
eanat_t start;
eanat_t end;
HANDLE handle;
highdll_range_t() : start(0), end(0), handle(INVALID_HANDLE_VALUE) {}
bool has(eanat_t addr) const { return addr >= start && addr < end; }
};
DECLARE_TYPE_AS_MOVABLE(highdll_range_t);
struct highdll_vec_t : protected qvector<highdll_range_t>
{
private:
size_t num_ntdlls; // count of actual ntdll*.dll modules in the list
public:
typedef qvector<highdll_range_t> inherited;
highdll_vec_t() : num_ntdlls(0) {}
void clear() { inherited::clear(); num_ntdlls = 0; }
size_t size() const { return inherited::size(); }
size_t count_ntdlls() const { return num_ntdlls; }
bool empty() const { return inherited::empty(); }
// return false if there is already a dll with such an address
bool add(eanat_t addr, size_t size, HANDLE h = INVALID_HANDLE_VALUE);
bool add_ntdll(eanat_t addr, size_t size, HANDLE h = INVALID_HANDLE_VALUE)
{
bool ok = add(addr, size, h);
if ( ok )
num_ntdlls++;
return ok;
};
// it returns true if the dll address doesn't fit in `ea_t`
bool add_high_module(
eanat_t addr,
size_t size,
HANDLE h = INVALID_HANDLE_VALUE);
// it returns true if the dll address doesn't fit to `ea_t`
bool del_high_module(HANDLE *h, eanat_t addr);
bool has(eanat_t addr) const;
};
//--------------------------------------------------------------------------
class winbase_debmod_t: public BASE_DEBUGGER_MODULE
{
typedef BASE_DEBUGGER_MODULE inherited;
wow64_state_t is_wow64; // use check_wow64_process()
protected:
HANDLE process_handle;
dep_policy_t dep_policy;
highdll_vec_t highdlls;
// local functions
bool mask_page_bpts(ea_t startea, ea_t endea, uint32 *protect);
void verify_page_protections(meminfo_vec_t *areas, const win32_prots_t &prots);
winbase_debmod_t(void);
// overridden virtual functions
bool idaapi dbg_enable_page_bpt(page_bpts_t::iterator p, bool enable);
int idaapi dbg_add_page_bpt(bpttype_t type, ea_t ea, int size);
bool check_for_call_large(const debug_event_t *event, HANDLE process_handle);
#ifndef __X86__
wow64_state_t check_wow64_process();
#else
wow64_state_t check_wow64_process() { return WOW64_NO; }
#endif
int get_process_addrsize(pid_t pid);
bool is_ntdll_name(const char *path);
// return number of processes, -1 - not implemented
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf) override;
// return the file name assciated with pid
virtual bool idaapi get_exec_fname(int pid, char *buf, size_t bufsize) newapi;
// get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
virtual int idaapi get_process_bitness(int pid) newapi;
public:
virtual void idaapi dbg_term(void) override;
static win_tool_help_t *get_tool_help();
static win_version_t winver;
private:
void build_process_ext_name(ext_process_info_t *pinfo);
static bool get_process_path(
ext_process_info_t *pinfo,
char *buf,
size_t bufsize);
static bool remove_page_protections(
DWORD *p_input,
bpttype_t bpttype,
dep_policy_t dpolicy,
HANDLE proc_handle);
static win_tool_help_t *win_tool_help;
};
bool should_fire_page_bpt(page_bpts_t::iterator p, ea_t ea, DWORD failed_access_type, ea_t pc, dep_policy_t dep_policy);
#ifdef _PE_H_
bool read_pe_header(peheader_t *pe);
#endif
//-------------------------------------------------------------------------
inline void tchar_utf8(qstring *buf, TCHAR *tchar)
{
#ifdef UNICODE
utf16_utf8(buf, tchar);
#else
acp_utf8(buf, tchar);
#endif
}
//-------------------------------------------------------------------------
inline void tchar_utf8(char *buf, TCHAR *tchar, size_t bufsize)
{
qstring utf8;
tchar_utf8(&utf8, tchar);
qstrncpy(buf, utf8.c_str(), bufsize);
}
#endif

125
idasdk75/defaults.mk Normal file
View File

@@ -0,0 +1,125 @@
#############################################################################
# versions and paths for various external libraries and utils
ifdef __NT__
# The following variables may have been set by vcvars.bat. You may
# also set them manually. The default installation directories are
# defined below in case these variables are not set.
# Note: the following paths use backslashes (and may also contain a
# trailing backslash) in order to conform to the variables
# exported by vcvars.bat.
# Visual C++ 2017 Install Directory
VCINSTALLDIR ?= '$(PROGRAMFILES)\Microsoft Visual Studio\2017\Professional\VC\'
# Visual C++ 2017 Tools Version
# Note: if this variable is not set, the default version is obtained
# in allmake.mak under "Visual C++ 2017 Tools Version".
# VCToolsVersion ?= '14.11.25503'
# Windows SDK Install Directory
WindowsSdkDir ?= '$(PROGRAMFILES)\Windows Kits\10\'
# Windows SDK version
# Note: if this variable is not set, the latest version is detected
# in allmake.mak under "Windows SDK Version".
# WindowsSDKVersion ?= '10.0.17134.0\'
# Microsoft SDK v7.1A is only used for the win32 debugger server for
# Windows XP compatibility.
MSSDK71_PATH = '$(PROGRAMFILES)/Microsoft SDKs/Windows/v7.1A'
else ifdef __MAC__
# oldest supported version of MacOSX
MACOSX_DEPLOYMENT_TARGET = 10.9
endif
# Python
PYTHON_VERSION_MAJOR?=3
PYTHON_VERSION_MINOR?=4
PYTHON_VERNAME=python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)
# TODO clean this up
ifdef __NT__
ifneq (,$(wildcard /cygdrive/c/Program\ Files/Python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR)/python.exe))
PYTHON_ROOT ?= C:/Program Files/Python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR)
else
ifeq ($(PYTHON_VERSION_MAJOR),2)
PYTHON_VERSUF=-x64
endif
PYTHON_ROOT ?= $(SYSTEMDRIVE)/Python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR)$(PYTHON_VERSUF)
endif
PYTHON ?= "$(PYTHON_ROOT)/python.exe"
else
PYTHON ?= $(PYTHON_VERNAME)
endif
# Qt
QTVER?=5.6.3-x64
QTDIR-$(__LINUX__) = /usr/local/Qt/$(QTVER)/
QTDIR-$(__MAC__) = /Users/Shared/Qt/$(QTVER)/
QTDIR-$(__NT__) = $(SYSTEMDRIVE)/Qt/$(QTVER)/
QTDIR ?= $(QTDIR-1)
ifdef __NT__
ifdef NDEBUG
QTSUFF=.dll
else
QTSUFF=d.dll
endif
QTLIBDIR=bin
else ifdef __LINUX__
QTPREF=lib
QTSUFF=.so.5
QTLIBDIR=lib
endif
# SWiG
ifeq ($(PYTHON_VERSION_MAJOR),3)
SWIG_VERSION?=4.0.1
ifdef __NT__
SWIG_DIR_SUFFIX?=-py3-stable-abi-cygwin
else
SWIG_DIR_SUFFIX?=-py3-stable-abi
endif
else
SWIG_VERSION?=4.0.0
endif
ifdef __NT__
ifeq ($(PYTHON_VERSION_MAJOR),3)
SWIG_DISTRIBUTION_HAS_UNIX_LAYOUT:=1
endif
else
SWIG_DISTRIBUTION_HAS_UNIX_LAYOUT:=1
endif
ifeq ($(SWIG_DISTRIBUTION_HAS_UNIX_LAYOUT),1)
ifdef USE_CCACHE
# we set CCACHE_DIR so as to not interfere with the system's ccache
# and we set CCACHE_CPP2 to prevent SWiG from printing a bunch of
# warnings due to re-using of the preprocessed source.
SWIG?=CCACHE_DIR='$${HOME}/.ccache-swig' CCACHE_CPP2=1 $(SWIG_HOME)/bin/ccache-swig $(SWIG_HOME)/bin/swig
else
SWIG?=$(SWIG_HOME)/bin/swig
endif
SWIG_INCLUDES?=-I$(SWIG_HOME)/share/swig/$(SWIG_VERSION)/python -I$(SWIG_HOME)/share/swig/$(SWIG_VERSION)
else
SWIG?=$(SWIG_HOME)/swig.exe
SWIG_INCLUDES?=-I$(SWIG_HOME)/Lib/python -I$(SWIG_HOME)/Lib
endif
#############################################################################
# keep all paths in unix format, with forward slashes
ifeq ($(OS),Windows_NT)
# define: convert dos path to unix path by replacing backslashes by slashes
unixpath=$(subst \,/,$(1))
PYTHON_ROOT :=$(call unixpath,$(PYTHON_ROOT))
PYTHON :=$(call unixpath,$(PYTHON))
SWIG :=$(call unixpath,$(SWIG))
QTDIR :=$(call unixpath,$(QTDIR))
endif
#############################################################################
# http://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile
.print-% : ; @echo $($*)

21042
idasdk75/include/allins.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
// this file should be included before calling deprecated functions
// it should be included at the point where the definitions of deprecated
// functions begin in the source file. this way a deprecated function may call
// another deprecated function without raising a warning.
// deprecated functions may call each other
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

289
idasdk75/include/auto.hpp Normal file
View File

@@ -0,0 +1,289 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _AUTO_HPP
#define _AUTO_HPP
#include <ida.hpp>
/*! \file auto.hpp
\brief Functions that work with the autoanalyzer queue.
The autoanalyzer works when IDA is not busy processing
the user keystrokes. It has several queues, each queue having
its own priority. The analyzer stops when all queues are empty.
A queue contains addresses or address ranges.
The addresses are kept sorted by their values.
The analyzer will process all addresses from the first queue, then
switch to the second queue and so on.
There are no limitations on the size of the queues.
This file also contains functions that deal with the IDA status
indicator and the autoanalysis indicator.
You may use these functions to change the indicator value.
*/
typedef int atype_t; ///< identifies an autoanalysis queue - see \ref AU_
/// \defgroup AU_ Autoanalysis queues
/// Names and priorities of the analyzer queues
//@{
const atype_t
AU_NONE = 00, ///< placeholder, not used
AU_UNK = 10, ///< 0: convert to unexplored
AU_CODE = 20, ///< 1: convert to instruction
AU_WEAK = 25, ///< 2: convert to instruction (ida decision)
AU_PROC = 30, ///< 3: convert to procedure start
AU_TAIL = 35, ///< 4: add a procedure tail
AU_FCHUNK=38, ///< 5: find func chunks
AU_USED = 40, ///< 6: reanalyze
AU_TYPE = 50, ///< 7: apply type information
AU_LIBF = 60, ///< 8: apply signature to address
AU_LBF2 = 70, ///< 9: the same, second pass
AU_LBF3 = 80, ///< 10: the same, third pass
AU_CHLB = 90, ///< 11: load signature file (file name is kept separately)
AU_FINAL=200; ///< 12: final pass
//@}
typedef int idastate_t; ///< IDA status indicator - see \ref st_
/// \defgroup st_ Status indicator states
//@{
const idastate_t
// meaning
st_Ready = 0, ///< READY: IDA is doing nothing
st_Think = 1, ///< THINKING: Autoanalysis on, the user may press keys
st_Waiting = 2, ///< WAITING: Waiting for the user input
st_Work = 3; ///< BUSY: IDA is busy
//@}
/// Get current state of autoanalyzer.
/// If auto_state == ::AU_NONE, IDA is currently not running the analysis
/// (it could be temporarily interrupted to perform the user's requests, for example).
idaman atype_t ida_export get_auto_state(void);
/// Set current state of autoanalyzer.
/// \param new_state new state of autoanalyzer
/// \return previous state
idaman atype_t ida_export set_auto_state(atype_t new_state);
/// See ::get_auto_display
struct auto_display_t
{
atype_t type = AU_NONE;
ea_t ea = BADADDR;
idastate_t state = st_Ready;
};
/// Get structure which holds the autoanalysis indicator contents
idaman bool ida_export get_auto_display(auto_display_t *auto_display);
/// Change autoanalysis indicator value.
/// \param ea linear address being analyzed
/// \param type autoanalysis type (see \ref AU_)
idaman void ida_export show_auto(ea_t ea, atype_t type=AU_NONE);
/// Show an address on the autoanalysis indicator.
/// The address is displayed in the form " @:12345678".
/// \param ea - linear address to display
inline void show_addr(ea_t ea) { show_auto(ea); }
/// Change IDA status indicator value
/// \param st - new indicator status
/// \return old indicator status
idaman idastate_t ida_export set_ida_state(idastate_t st);
/// Is it allowed to create stack variables automatically?.
/// This function should be used by IDP modules before creating stack vars.
inline bool may_create_stkvars(void)
{
return inf_should_create_stkvars() && get_auto_state() == AU_USED;
}
/// Is it allowed to trace stack pointer automatically?.
/// This function should be used by IDP modules before tracing sp.
inline bool may_trace_sp(void)
{
if ( inf_should_trace_sp() )
{
atype_t auto_state = get_auto_state();
return auto_state == AU_USED;
}
return false;
}
/// Put range of addresses into a queue.
/// 'start' may be higher than 'end', the kernel will swap them in this case.
/// 'end' doesn't belong to the range.
idaman void ida_export auto_mark_range(ea_t start,ea_t end,atype_t type);
/// Put single address into a queue. Queues keep addresses sorted.
inline void auto_mark(ea_t ea, atype_t type)
{
auto_mark_range(ea, ea+1, type);
}
/// Remove range of addresses from a queue.
/// 'start' may be higher than 'end', the kernel will swap them in this case.
/// 'end' doesn't belong to the range.
idaman void ida_export auto_unmark(ea_t start, ea_t end, atype_t type);
// Convenience functions
/// Plan to perform reanalysis
inline void plan_ea(ea_t ea)
{
auto_mark(ea, AU_USED);
}
/// Plan to perform reanalysis
inline void plan_range(ea_t sEA, ea_t eEA)
{
auto_mark_range(sEA, eEA, AU_USED);
}
/// Plan to make code
inline void auto_make_code(ea_t ea)
{
auto_mark(ea, AU_CODE);
}
/// Plan to make code&function
inline void auto_make_proc(ea_t ea)
{
auto_make_code(ea);
auto_mark(ea, AU_PROC);
}
/// Plan to reanalyze callers of the specified address.
/// This function will add to ::AU_USED queue all instructions that
/// call (not jump to) the specified address.
/// \param ea linear address of callee
/// \param noret !=0: the callee doesn't return, mark to undefine subsequent
/// instructions in the caller. 0: do nothing.
idaman void ida_export reanalyze_callers(ea_t ea, bool noret);
/// Delete all analysis info that IDA generated for for the given range
idaman void ida_export revert_ida_decisions(ea_t ea1, ea_t ea2);
/// Plan to apply the callee's type to the calling point
idaman void ida_export auto_apply_type(ea_t caller, ea_t callee);
/// Plan to apply the tail_ea chunk to the parent
/// \param tail_ea linear address of start of tail
/// \param parent_ea linear address within parent. If BADADDR, automatically
/// try to find parent via xrefs.
idaman void ida_export auto_apply_tail(ea_t tail_ea, ea_t parent_ea);
/// Analyze the specified range.
/// Try to create instructions where possible.
/// Make the final pass over the specified range if specified.
/// This function doesn't return until the range is analyzed.
/// \retval 1 ok
/// \retval 0 Ctrl-Break was pressed
idaman int ida_export plan_and_wait(ea_t ea1, ea_t ea2, bool final_pass=true);
/// Process everything in the queues and return true.
/// \return false if the user clicked cancel.
/// (the wait box must be displayed by the caller if desired)
idaman bool ida_export auto_wait(void);
/// Process everything in the specified range and return true.
/// \return number of autoanalysis steps made. -1 if the user clicked cancel.
/// (the wait box must be displayed by the caller if desired)
idaman ssize_t ida_export auto_wait_range(ea_t ea1, ea_t ea2);
/// Analyze one address in the specified range and return true.
/// \return if processed anything. false means that there is nothing to
/// process in the specified range.
idaman bool ida_export auto_make_step(ea_t ea1, ea_t ea2);
/// Remove an address range (ea1..ea2) from queues ::AU_CODE, ::AU_PROC, ::AU_USED.
/// To remove an address range from other queues use auto_unmark() function.
/// 'ea1' may be higher than 'ea2', the kernel will swap them in this case.
/// 'ea2' doesn't belong to the range.
idaman void ida_export auto_cancel(ea_t ea1, ea_t ea2);
/// Are all queues empty?
/// (i.e. has autoanalysis finished?).
idaman bool ida_export auto_is_ok(void);
/// Peek into a queue 'type' for an address not lower than 'low_ea'.
/// Do not remove address from the queue.
/// \return the address or #BADADDR
idaman ea_t ida_export peek_auto_queue(ea_t low_ea, atype_t type);
/// Retrieve an address from queues regarding their priority.
/// Returns #BADADDR if no addresses not lower than 'lowEA' and less than
/// 'highEA' are found in the queues.
/// Otherwise *type will have queue type.
idaman ea_t ida_export auto_get(atype_t *type, ea_t lowEA, ea_t highEA);
/// Try to create instruction
/// \param ea linear address of callee
/// \return the length of the instruction or 0
idaman int ida_export auto_recreate_insn(ea_t ea);
/// Get autoanalyzer state
idaman bool ida_export is_auto_enabled(void);
/// Temporarily enable/disable autoanalyzer. Not user-facing, but rather because
/// IDA sometimes need to turn AA on/off regardless of inf.s_genflags:INFFL_AUTO
/// \return old state
idaman bool ida_export enable_auto(bool enable);
#endif // _AUTO_HPP

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