718 lines
22 KiB
C++
718 lines
22 KiB
C++
//
|
|
//
|
|
// 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 ∋
|
|
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;
|
|
}
|