Files
sigmaker-ida/idasdk75/dbg/win32/win32_debmod.h
2021-06-05 21:10:25 +03:00

429 lines
15 KiB
C++

#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